Starbeam

Embedded demos

One table model, multiple framework edges.

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.

Shared source Table model @starbeam-demos/table-core/src/table.ts React, Preact, Vue, Svelte, and Ember shells import this package. Show code Hide code

Ordinary TypeScript owns the table state. The framework shells only decide how reads connect to rendering.

Universal source @starbeam-demos/table-core/src/table.ts
import {
const reactive: {
Map<K, V>(description?: string): Map<K, V>;
}
reactive
} from "@starbeam/collections";
export type
type RowId = string
RowId
= string;
export interface
interface TableRow
TableRow
{
readonly
TableRow.id: string
id
:
type RowId = string
RowId
;
}
export interface
interface ViewOptions<Row extends TableRow>
ViewOptions
<
function (type parameter) Row in ViewOptions<Row extends TableRow>
Row
extends
interface TableRow
TableRow
> {
readonly
ViewOptions<Row extends TableRow>.filter?: ((row: Row) => boolean) | undefined
filter
?: (
row: Row extends TableRow
row
:
function (type parameter) Row in ViewOptions<Row extends TableRow>
Row
) => boolean;
readonly
ViewOptions<Row extends TableRow>.sort?: ((left: Row, right: Row) => number) | undefined
sort
?: (
left: Row extends TableRow
left
:
function (type parameter) Row in ViewOptions<Row extends TableRow>
Row
,
right: Row extends TableRow
right
:
function (type parameter) Row in ViewOptions<Row extends TableRow>
Row
) => number;
}
export interface
interface TableView<Row extends TableRow>
TableView
<
function (type parameter) Row in TableView<Row extends TableRow>
Row
extends
interface TableRow
TableRow
> {
readonly
TableView<Row extends TableRow>.rows: readonly Row[]
rows
: readonly
function (type parameter) Row in TableView<Row extends TableRow>
Row
[];
readonly
TableView<Row extends TableRow>.count: number
count
: number;
}
export class
class Table<Row extends TableRow>
Table
<
function (type parameter) Row in Table<Row extends TableRow>
Row
extends
interface TableRow
TableRow
> {
readonly #rows =
const reactive: {
Map<K, V>(description?: string): Map<K, V>;
}
reactive
.
Map<string, Row>(description?: string): Map<string, Row>
Map
<
type RowId = string
RowId
,
function (type parameter) Row in Table<Row extends TableRow>
Row
>("table rows");
#rowArray():
function (type parameter) Row in Table<Row extends TableRow>
Row
[] {
return [...this.#rows.
Map<string, Row>.values(): MapIterator<Row>

Returns an iterable of values in the map

values
()];
}
get
Table<Row extends TableRow>.size: number
size
(): number {
return this.#rows.
Map<string, Row>.size: number

@returns โ€• the number of elements in the Map.

size
;
}
get
Table<Row extends TableRow>.rows: readonly Row[]
rows
(): readonly
function (type parameter) Row in Table<Row extends TableRow>
Row
[] {
return this.#rowArray();
}
Table<Row extends TableRow>.clear(): void
clear
(): void {
this.#rows.
Map<string, Row>.clear(): void

Removes all elements from the Map.

clear
();
}
Table<Row extends TableRow>.delete(id: RowId): boolean
delete
(
id: string
id
:
type RowId = string
RowId
): boolean {
return this.#rows.
Map<string, Row>.delete(key: string): boolean

@returns โ€• true if an element in the Map existed and has been removed, or false if the element does not exist.

delete
(
id: string
id
);
}
Table<Row extends TableRow>.get(id: RowId): Row | undefined
get
(
id: string
id
:
type RowId = string
RowId
):
function (type parameter) Row in Table<Row extends TableRow>
Row
| undefined {
return this.#rows.
Map<string, Row>.get(key: string): Row | undefined

Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.

@returns โ€• Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.

get
(
id: string
id
);
}
Table<Row extends TableRow>.insert(row: Row): void
insert
(
row: Row extends TableRow
row
:
function (type parameter) Row in Table<Row extends TableRow>
Row
): void {
if (this.#rows.
Map<string, Row>.has(key: string): boolean

@returns โ€• boolean indicating whether an element with the specified key exists or not.

has
(
row: Row extends TableRow
row
.
TableRow.id: string
id
)) {
throw new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
(`Row already exists: ${
row: Row extends TableRow
row
.
TableRow.id: string
id
}`);
}
this.#rows.
Map<string, Row>.set(key: string, value: Row): Map<string, Row>

Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.

set
(
row: Row extends TableRow
row
.
TableRow.id: string
id
,
row: Row extends TableRow
row
);
}
Table<Row extends TableRow>.update(id: RowId, updater: (row: Row) => Row): Row
update
(
id: string
id
:
type RowId = string
RowId
,
updater: (row: Row) => Row
updater
: (
row: Row extends TableRow
row
:
function (type parameter) Row in Table<Row extends TableRow>
Row
) =>
function (type parameter) Row in Table<Row extends TableRow>
Row
):
function (type parameter) Row in Table<Row extends TableRow>
Row
{
const
const row: Row | undefined
row
= this.#rows.
Map<string, Row>.get(key: string): Row | undefined

Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.

@returns โ€• Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.

get
(
id: string
id
);
if (!
const row: Row | undefined
row
) {
throw new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
(`Row not found: ${
id: string
id
}`);
}
const
const next: Row extends TableRow
next
=
updater: (row: Row) => Row
updater
(
const row: Row extends TableRow
row
);
if (
const next: Row extends TableRow
next
.
TableRow.id: string
id
!==
id: string
id
) {
throw new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
("Table.update() cannot change a row id");
}
this.#rows.
Map<string, Row>.set(key: string, value: Row): Map<string, Row>

Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.

set
(
id: string
id
,
const next: Row extends TableRow
next
);
return
const next: Row extends TableRow
next
;
}
Table<Row extends TableRow>.upsert(row: Row): void
upsert
(
row: Row extends TableRow
row
:
function (type parameter) Row in Table<Row extends TableRow>
Row
): void {
this.#rows.
Map<string, Row>.set(key: string, value: Row): Map<string, Row>

Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.

set
(
row: Row extends TableRow
row
.
TableRow.id: string
id
,
row: Row extends TableRow
row
);
}
Table<Row extends TableRow>.view(options?: ViewOptions<Row>): TableView<Row>
view
(
options: ViewOptions<Row>
options
:
interface ViewOptions<Row extends TableRow>
ViewOptions
<
function (type parameter) Row in Table<Row extends TableRow>
Row
> = {}):
interface TableView<Row extends TableRow>
TableView
<
function (type parameter) Row in Table<Row extends TableRow>
Row
> {
let
let rows: Row[]
rows
= this.#rowArray();
if (
options: ViewOptions<Row>
options
.
ViewOptions<Row>.filter?: ((row: Row) => boolean) | undefined
filter
) {
let rows: Row[]
rows
=
let rows: Row[]
rows
.
Array<Row>.filter(predicate: (value: Row, index: number, array: Row[]) => unknown, thisArg?: any): Row[] (+1 overload)

Returns the elements of an array that meet the condition specified in a callback function.

@param โ€• predicate A function that accepts up to three arguments. The filter method calls the predicate function one time for each element in the array.

@param โ€• thisArg An object to which the this keyword can refer in the predicate function. If thisArg is omitted, undefined is used as the this value.

filter
(
options: ViewOptions<Row>
options
.
ViewOptions<Row>.filter?: (row: Row) => boolean
filter
);
}
if (
options: ViewOptions<Row>
options
.
ViewOptions<Row>.sort?: ((left: Row, right: Row) => number) | undefined
sort
) {
let rows: Row[]
rows
=
let rows: Row[]
rows
.
Array<Row>.sort(compareFn?: ((a: Row, b: Row) => number) | undefined): Row[]

Sorts an array in place. This method mutates the array and returns a reference to the same array.

@param โ€•

compareFn Function used to determine the order of the elements. It is expected to return a negative value if the first argument is less than the second argument, zero if they're equal, and a positive value otherwise. If omitted, the elements are sorted in ascending, UTF-16 code unit order.

[11,2,22,1].sort((a, b) => a - b)

sort
(
options: ViewOptions<Row>
options
.
ViewOptions<Row>.sort?: (left: Row, right: Row) => number
sort
);
}
return {
TableView<Row>.rows: readonly Row[]
rows
,
TableView<Row extends TableRow>.count: number
count
:
let rows: Row[]
rows
.
Array<Row>.length: number

Gets or sets the length of the array. This is a number one higher than the highest index in the array.

length
};
}
}
export function
function createTable<Row extends TableRow>(): Table<Row>
createTable
<
function (type parameter) Row in createTable<Row extends TableRow>(): Table<Row>
Row
extends
interface TableRow
TableRow
>():
class Table<Row extends TableRow>
Table
<
function (type parameter) Row in createTable<Row extends TableRow>(): Table<Row>
Row
> {
return new
constructor Table<Row>(): Table<Row>
Table
<
function (type parameter) Row in createTable<Row extends TableRow>(): Table<Row>
Row
>();
}
export type
type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory
= "produce" | "bakery" | "pantry" | "dairy";
export interface
interface InventoryItem
InventoryItem
extends
interface TableRow
TableRow
{
readonly
InventoryItem.name: string
name
: string;
readonly
InventoryItem.category: InventoryCategory
category
:
type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory
;
readonly
InventoryItem.price: number
price
: number;
readonly
InventoryItem.stock: number
stock
: number;
}
export interface
interface InventoryStats
InventoryStats
{
readonly
InventoryStats.categories: ReadonlyMap<InventoryCategory, number>
categories
:
interface ReadonlyMap<K, V>
ReadonlyMap
<
type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory
, number>;
readonly
InventoryStats.inventoryValue: number
inventoryValue
: number;
readonly
InventoryStats.lowStockCount: number
lowStockCount
: number;
readonly
InventoryStats.totalItems: number
totalItems
: number;
}
const
const EMPTY_COUNT: 0
EMPTY_COUNT
= 0;
const
const ONE_ITEM: 1
ONE_ITEM
= 1;
export const
const LOW_STOCK_THRESHOLD: 5
LOW_STOCK_THRESHOLD
= 5;
export class
class Inventory
Inventory
{
readonly #table =
function createTable<InventoryItem>(): Table<InventoryItem>
createTable
<
interface InventoryItem
InventoryItem
>();
get
Inventory.rows: readonly InventoryItem[]
rows
(): readonly
interface InventoryItem
InventoryItem
[] {
return this.#table.
Table<InventoryItem>.rows: readonly InventoryItem[]
rows
;
}
get
Inventory.stats: InventoryStats
stats
():
interface InventoryStats
InventoryStats
{
const
const categories: Map<InventoryCategory, number>
categories
= new
var Map: MapConstructor
new <InventoryCategory, number>(iterable?: Iterable<readonly [InventoryCategory, number]> | null | undefined) => Map<InventoryCategory, number> (+3 overloads)
Map
<
type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory
, number>();
const
const rows: readonly InventoryItem[]
rows
= this.
Inventory.rows: readonly InventoryItem[]
rows
;
let
let inventoryValue: number
inventoryValue
= 0;
let
let lowStockCount: number
lowStockCount
= 0;
for (const
const item: InventoryItem
item
of
const rows: readonly InventoryItem[]
rows
) {
const categories: Map<InventoryCategory, number>
categories
.
Map<InventoryCategory, number>.set(key: InventoryCategory, value: number): Map<InventoryCategory, number>

Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.

set
(
const item: InventoryItem
item
.
InventoryItem.category: InventoryCategory
category
,
(
const categories: Map<InventoryCategory, number>
categories
.
Map<InventoryCategory, number>.get(key: InventoryCategory): number | undefined

Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.

@returns โ€• Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.

get
(
const item: InventoryItem
item
.
InventoryItem.category: InventoryCategory
category
) ??
const EMPTY_COUNT: 0
EMPTY_COUNT
) +
const ONE_ITEM: 1
ONE_ITEM
,
);
let inventoryValue: number
inventoryValue
+=
const item: InventoryItem
item
.
InventoryItem.price: number
price
*
const item: InventoryItem
item
.
InventoryItem.stock: number
stock
;
if (
const item: InventoryItem
item
.
InventoryItem.stock: number
stock
<=
const LOW_STOCK_THRESHOLD: 5
LOW_STOCK_THRESHOLD
) {
let lowStockCount: number
lowStockCount
++;
}
}
return {
InventoryStats.categories: ReadonlyMap<InventoryCategory, number>
categories
,
InventoryStats.inventoryValue: number
inventoryValue
,
InventoryStats.lowStockCount: number
lowStockCount
,
InventoryStats.totalItems: number
totalItems
:
const rows: readonly InventoryItem[]
rows
.
ReadonlyArray<InventoryItem>.length: number

Gets the length of the array. This is a number one higher than the highest element defined in an array.

length
,
};
}
Inventory.add(item: InventoryItem): void
add
(
item: InventoryItem
item
:
interface InventoryItem
InventoryItem
): void {
this.#table.
Table<InventoryItem>.insert(row: InventoryItem): void
insert
(
item: InventoryItem
item
);
}
Inventory.clear(): void
clear
(): void {
this.#table.
Table<InventoryItem>.clear(): void
clear
();
}
Inventory.delete(id: RowId): boolean
delete
(
id: string
id
:
type RowId = string
RowId
): boolean {
return this.#table.
Table<InventoryItem>.delete(id: RowId): boolean
delete
(
id: string
id
);
}
Inventory.find(id: RowId): InventoryItem | undefined
find
(
id: string
id
:
type RowId = string
RowId
):
interface InventoryItem
InventoryItem
| undefined {
return this.#table.
Table<InventoryItem>.get(id: RowId): InventoryItem | undefined
get
(
id: string
id
);
}
Inventory.restock(id: RowId, amount: number): InventoryItem
restock
(
id: string
id
:
type RowId = string
RowId
,
amount: number
amount
: number):
interface InventoryItem
InventoryItem
{
return this.
Inventory.update(id: RowId, updater: (item: InventoryItem) => InventoryItem): InventoryItem
update
(
id: string
id
, (
item: InventoryItem
item
) => ({ ...
item: InventoryItem
item
,
InventoryItem.stock: number
stock
:
item: InventoryItem
item
.
InventoryItem.stock: number
stock
+
amount: number
amount
}));
}
Inventory.update(id: RowId, updater: (item: InventoryItem) => InventoryItem): InventoryItem
update
(
id: string
id
:
type RowId = string
RowId
,
updater: (item: InventoryItem) => InventoryItem
updater
: (
item: InventoryItem
item
:
interface InventoryItem
InventoryItem
) =>
interface InventoryItem
InventoryItem
,
):
interface InventoryItem
InventoryItem
{
return this.#table.
Table<InventoryItem>.update(id: RowId, updater: (row: InventoryItem) => InventoryItem): InventoryItem
update
(
id: string
id
,
updater: (item: InventoryItem) => InventoryItem
updater
);
}
Inventory.upsert(item: InventoryItem): void
upsert
(
item: InventoryItem
item
:
interface InventoryItem
InventoryItem
): void {
this.#table.
Table<InventoryItem>.upsert(row: InventoryItem): void
upsert
(
item: InventoryItem
item
);
}
Inventory.view(options?: InventoryViewOptions): TableView<InventoryItem>
view
(
options: InventoryViewOptions
options
:
interface InventoryViewOptions
InventoryViewOptions
= {}):
interface TableView<Row extends TableRow>
TableView
<
interface InventoryItem
InventoryItem
> {
return this.#table.
Table<InventoryItem>.view(options?: ViewOptions<InventoryItem>): TableView<InventoryItem>
view
({
ViewOptions<InventoryItem>.filter?: ((row: InventoryItem) => boolean) | undefined
filter
: (
item: InventoryItem
item
) =>
function matchesInventoryFilters(item: InventoryItem, options: InventoryViewOptions): boolean
matchesInventoryFilters
(
item: InventoryItem
item
,
options: InventoryViewOptions
options
),
ViewOptions<InventoryItem>.sort?: ((left: InventoryItem, right: InventoryItem) => number) | undefined
sort
:
function sortInventory(sort?: InventoryViewOptions["sort"]): (left: InventoryItem, right: InventoryItem) => number
sortInventory
(
options: InventoryViewOptions
options
.
InventoryViewOptions.sort?: "name" | "category" | "stock" | "value" | undefined
sort
),
});
}
}
export interface
interface InventoryViewOptions
InventoryViewOptions
{
readonly
InventoryViewOptions.category?: InventoryCategory | "all" | undefined
category
?:
type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory
| "all";
readonly
InventoryViewOptions.lowStockOnly?: boolean | undefined
lowStockOnly
?: boolean;
readonly
InventoryViewOptions.search?: string | undefined
search
?: string;
readonly
InventoryViewOptions.sort?: "name" | "category" | "stock" | "value" | undefined
sort
?: "name" | "category" | "stock" | "value";
}
export function
function createInventory(items?: Iterable<InventoryItem>): Inventory
createInventory
(
items: Iterable<InventoryItem>
items
:
interface Iterable<T, TReturn = any, TNext = any>
Iterable
<
interface InventoryItem
InventoryItem
> = [],
):
class Inventory
Inventory
{
const
const inventory: Inventory
inventory
= new
constructor Inventory(): Inventory
Inventory
();
for (const
const item: InventoryItem
item
of
items: Iterable<InventoryItem>
items
) {
const inventory: Inventory
inventory
.
Inventory.add(item: InventoryItem): void
add
(
const item: InventoryItem
item
);
}
return
const inventory: Inventory
inventory
;
}
function
function matchesInventoryFilters(item: InventoryItem, options: InventoryViewOptions): boolean
matchesInventoryFilters
(
item: InventoryItem
item
:
interface InventoryItem
InventoryItem
,
options: InventoryViewOptions
options
:
interface InventoryViewOptions
InventoryViewOptions
,
): boolean {
if (
options: InventoryViewOptions
options
.
InventoryViewOptions.category?: InventoryCategory | "all" | undefined
category
&&
options: InventoryViewOptions
options
.
InventoryViewOptions.category?: InventoryCategory | "all"
category
!== "all") {
if (
item: InventoryItem
item
.
InventoryItem.category: InventoryCategory
category
!==
options: InventoryViewOptions
options
.
InventoryViewOptions.category?: InventoryCategory
category
) {
return false;
}
}
if (
options: InventoryViewOptions
options
.
InventoryViewOptions.lowStockOnly?: boolean | undefined
lowStockOnly
=== true &&
item: InventoryItem
item
.
InventoryItem.stock: number
stock
>
const LOW_STOCK_THRESHOLD: 5
LOW_STOCK_THRESHOLD
) {
return false;
}
if (
options: InventoryViewOptions
options
.
InventoryViewOptions.search?: string | undefined
search
) {
return
item: InventoryItem
item
.
InventoryItem.name: string
name
.
String.toLowerCase(): string

Converts all the alphabetic characters in a string to lowercase.

toLowerCase
().
String.includes(searchString: string, position?: number): boolean

Returns true if searchString appears as a substring of the result of converting this object to a String, at one or more positions that are greater than or equal to position; otherwise, returns false.

@param โ€• searchString search string

@param โ€• position If position is undefined, 0 is assumed, so as to search all of the String.

includes
(
options: InventoryViewOptions
options
.
InventoryViewOptions.search?: string
search
.
String.toLowerCase(): string

Converts all the alphabetic characters in a string to lowercase.

toLowerCase
());
}
return true;
}
function
function sortInventory(sort?: InventoryViewOptions["sort"]): (left: InventoryItem, right: InventoryItem) => number
sortInventory
(
sort: "name" | "category" | "stock" | "value" | undefined
sort
:
interface InventoryViewOptions
InventoryViewOptions
["sort"] = "name",
): (
left: InventoryItem
left
:
interface InventoryItem
InventoryItem
,
right: InventoryItem
right
:
interface InventoryItem
InventoryItem
) => number {
switch (
sort: "name" | "category" | "stock" | "value"
sort
) {
case "category":
return (
left: InventoryItem
left
,
right: InventoryItem
right
) =>
left: InventoryItem
left
.
InventoryItem.category: InventoryCategory
category
.
String.localeCompare(that: string, locales?: Intl.LocalesArgument, options?: Intl.CollatorOptions): number (+2 overloads)

Determines whether two strings are equivalent in the current or specified locale.

@param โ€• that String to compare to target string

@param โ€• locales A locale string or array of locale strings that contain one or more language or locale tags. If you include more than one locale string, list them in descending order of priority so that the first entry is the preferred locale. If you omit this parameter, the default locale of the JavaScript runtime is used. This parameter must conform to BCP 47 standards; see the Intl.Collator object for details.

@param โ€• options An object that contains one or more properties that specify comparison options. see the Intl.Collator object for details.

localeCompare
(
right: InventoryItem
right
.
InventoryItem.category: InventoryCategory
category
) ||
left: InventoryItem
left
.
InventoryItem.name: string
name
.
String.localeCompare(that: string, locales?: Intl.LocalesArgument, options?: Intl.CollatorOptions): number (+2 overloads)

Determines whether two strings are equivalent in the current or specified locale.

@param โ€• that String to compare to target string

@param โ€• locales A locale string or array of locale strings that contain one or more language or locale tags. If you include more than one locale string, list them in descending order of priority so that the first entry is the preferred locale. If you omit this parameter, the default locale of the JavaScript runtime is used. This parameter must conform to BCP 47 standards; see the Intl.Collator object for details.

@param โ€• options An object that contains one or more properties that specify comparison options. see the Intl.Collator object for details.

localeCompare
(
right: InventoryItem
right
.
InventoryItem.name: string
name
);
case "stock":
return (
left: InventoryItem
left
,
right: InventoryItem
right
) =>
left: InventoryItem
left
.
InventoryItem.stock: number
stock
-
right: InventoryItem
right
.
InventoryItem.stock: number
stock
;
case "value":
return (
left: InventoryItem
left
,
right: InventoryItem
right
) =>
right: InventoryItem
right
.
InventoryItem.price: number
price
*
right: InventoryItem
right
.
InventoryItem.stock: number
stock
-
left: InventoryItem
left
.
InventoryItem.price: number
price
*
left: InventoryItem
left
.
InventoryItem.stock: number
stock
;
case "name":
return (
left: InventoryItem
left
,
right: InventoryItem
right
) =>
left: InventoryItem
left
.
InventoryItem.name: string
name
.
String.localeCompare(that: string, locales?: Intl.LocalesArgument, options?: Intl.CollatorOptions): number (+2 overloads)

Determines whether two strings are equivalent in the current or specified locale.

@param โ€• that String to compare to target string

@param โ€• locales A locale string or array of locale strings that contain one or more language or locale tags. If you include more than one locale string, list them in descending order of priority so that the first entry is the preferred locale. If you omit this parameter, the default locale of the JavaScript runtime is used. This parameter must conform to BCP 47 standards; see the Intl.Collator object for details.

@param โ€• options An object that contains one or more properties that specify comparison options. see the Intl.Collator object for details.

localeCompare
(
right: InventoryItem
right
.
InventoryItem.name: string
name
);
}
}

Framework shells

Same model, five framework edges.

The React shell wraps the table read in useReactive() and keeps mutations in event handlers.

Framework source React shell App.tsx Show code Hide code
React shell @starbeam-demos/table-react/src/App.tsx
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 InventoryItem
import InventoryItem
InventoryItem
,
(alias) interface InventoryViewOptions
import 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 JSX
import 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.

@version โ€• 16.8.0

@see โ€• https://react.dev/reference/react/useState

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 InventoryViewOptions
import 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 JSX
import 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.

@version โ€• 16.8.0

@see โ€• https://react.dev/reference/react/useState

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.

@version โ€• 16.8.0

@see โ€• https://react.dev/reference/react/useState

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.

@version โ€• 16.8.0

@see โ€• https://react.dev/reference/react/useState

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.

@version โ€• 16.8.0

@see โ€• https://react.dev/reference/react/useState

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.

@version โ€• 16.8.0

@see โ€• https://react.dev/reference/react/useState

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.

@param โ€• callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.

@param โ€• thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.

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.

@see โ€• aria-labelledby.

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.

@param โ€• radix Specifies a radix for converting numeric values to strings. This value is only used for numbers.

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.

@param โ€• radix Specifies a radix for converting numeric values to strings. This value is only used for numbers.

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.

@see โ€• aria-labelledby.

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.

MDN Reference

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.

MDN Reference

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.

@param โ€• callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.

@param โ€• thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.

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.

MDN Reference

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.

MDN Reference

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.

@see โ€• aria-labelledby.

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.

MDN Reference

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.

@see โ€• aria-labelledby.

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.

@param โ€• callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.

@param โ€• thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.

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.

@param โ€• callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.

@param โ€• thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.

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.

@param โ€• searchValue A string to search for.

@param โ€• replaceValue A string containing the text to replace for every successful match of searchValue in this 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 InventoryItem
import InventoryItem
InventoryItem
}):
(alias) namespace JSX
import 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 InventoryItem
import InventoryItem
InventoryItem
) =>
(alias) interface InventoryItem
import 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.

@see โ€• aria-labelledby.

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.

MDN Reference

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.

MDN Reference

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.

@param โ€• callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.

@param โ€• thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.

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.

MDN Reference

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.

MDN Reference

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 JSX
import 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.NumberFormatConstructor
new (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`;
}