Skip to main content

Build warnings

Every warning links to its section here. A line with more than one fault raises a warning for each, except inside one defineEditableSource() call: a declaration reports its first fault, so fixing one can reveal the next.

These warnings are only shown for a deck on project file version 4. A deck below it sees none of them.

Warnings marked Shown with undiscoveredEditables print only with that flag on. They list everything the build could not discover, so turn it on while upgrading a deck:

.deckrc.json
{
"warnings": { "undiscoveredEditables": true }
}

Markup​

key-not-written-out​

warningReactVanilla

An editable key has to be written out as a string, so the build can add it to the built project. If you write it as an expression, the build cannot read the code, and the AI assistant won't be able to use the field.

Shown with undiscoveredEditables

WARNING in ⚠ editable discovery (key-not-written-out)
The build cannot read fieldKey in data-editable={fieldKey}, so the AI assistant won't be able to use the field.
Fix, one of:
Write the key out:
data-editable="a-field"
If the key differs at each place it is rendered, declare what renders it:
defineEditableSource(YourEditable, { ... })
Before
export function Headline({ fieldKey }) {
return <p data-editable={fieldKey}>Our plans</p>;
}

<Headline fieldKey="title" />;
After: write the key out
export function Headline() {
return <p data-editable="title">Our plans</p>;
}

<Headline />;
After: declare what renders it
import { defineEditableSource, resolveEditable } from "@livepreso/webpack-deck";

export function Headline(props) {
const { attrs } = resolveEditable(editable, props);

return <p {...attrs}>Our plans</p>;
}

const editable = defineEditableSource(Headline, {
personal: { key: "{targetKey}-{id}-{instance}" },
});

<Headline id="title" />;

See:

toolbar-not-written-out​

warningReactVanilla

A data-toolbar has to be written out as a string of option names. If you write it as an expression, the build cannot read the code. It will work for a user, but the AI assistant won't be able to use it.

Shown with undiscoveredEditables

WARNING in ⚠ editable discovery (toolbar-not-written-out)
The build cannot read toolbarOptions in data-toolbar={toolbarOptions}, so the AI assistant won't be able to edit the field. A user can still edit with the toolbar.
Fix, one of:
Write the toolbar out:
data-toolbar="style color"
If the toolbar arrives as an argument, declare what renders it:
defineEditableSource(YourEditable, { ... })
Before
export function Notes({ toolbarOptions }) {
return (
<div data-editable="notes" data-toolbar={toolbarOptions}>
Our notes
</div>
);
}

<Notes toolbarOptions="style color" />;
After: write the toolbar out
export function Notes() {
return (
<div data-editable="notes" data-toolbar="style color">
Our notes
</div>
);
}

<Notes />;
After: declare what renders it
import { defineEditableSource, resolveEditable } from "@livepreso/webpack-deck";

export function Notes(props) {
const { attrs } = resolveEditable(editable, props);

return <div {...attrs}>Our notes</div>;
}

const editable = defineEditableSource(Notes, {
personal: { key: "{targetKey}-{id}-{instance}" },
});

<Notes id="notes" toolbar={["style", "color"]} />;

See:

toolbar-option-not-recognised​

warningReactVanilla

Every option in a data-toolbar has to be an allowed option. Otherwise the AI assistant won't be able to edit the field.

WARNING in ⚠ editable discovery (toolbar-option-not-recognised)
data-toolbar="style colour" includes colour.
A data-toolbar option can only be style, color, superscript, link, align, removeformat, list, table or format. The AI assistant won't be able to edit the field until every option is one of these.
Fix: change or remove colour.
Before
<div data-editable="notes" data-toolbar="style colour">
Our notes
</div>
After: change the option
<div data-editable="notes" data-toolbar="style color">
Our notes
</div>
After: remove the option
<div data-editable="notes" data-toolbar="style">
Our notes
</div>

See:

toolbar-option-needs-a-div​

warningReactVanilla

The list and table options only work on a <div>. On any other element the editor leaves those buttons out.

WARNING in ⚠ editable discovery (toolbar-option-needs-a-div)
data-toolbar="style list" is on a <p>. The editor won't offer list on a <p>, only on a <div>.
Fix, one of:
Change the <p> to a <div>.
Remove list from data-toolbar.
Before
<p data-editable="notes" data-toolbar="style list">
Our notes
</p>
After: change the tag to a div
<div data-editable="notes" data-toolbar="style list">
Our notes
</div>
After: remove the option
<p data-editable="notes" data-toolbar="style">
Our notes
</p>

See:

attribute-on-a-component​

warningReact

An editable attribute written on a component only reaches the page if the component passes it on to an element. If it doesn't, the field won't appear on the page, but the AI assistant can still edit it. A component that spreads all of its props onto an element passes it on, and raises nothing.

Shown with undiscoveredEditables

WARNING in ⚠ editable discovery (attribute-on-a-component)
data-editable="title" is on <Headline>.
Headline is a component, so data-editable only reaches the page if Headline passes it on to an element. If it doesn't, the field won't appear on the page, but the AI assistant can still edit it.
Fix, one of:
Move data-editable onto the element Headline renders.
Have Headline pass its props on to that element:
<Headline data-editable="title" />
If the key differs at each place it is rendered, declare what renders it:
defineEditableSource(YourEditable, { ... })
Before
export function Headline() {
return <p className="headline">Our plans</p>;
}

<Headline data-editable="title" />;
After: move it onto the element
export function Headline() {
return (
<p className="headline" data-editable="title">
Our plans
</p>
);
}

<Headline />;
After: declare what renders it
import { defineEditableSource, resolveEditable } from "@livepreso/webpack-deck";

export function Headline(props) {
const { attrs } = resolveEditable(editable, props);

return (
<p className="headline" {...attrs}>
Our plans
</p>
);
}

const editable = defineEditableSource(Headline, {
personal: { key: "{targetKey}-{id}-{instance}" },
});

<Headline id="title" />;
After: pass it on
export function Headline(props) {
return (
<p className="headline" {...props}>
Our plans
</p>
);
}

<Headline data-editable="title" />;

See:

markers-built-into-an-object​

warningReactVanilla

You put an editable attribute in an object and spread the object onto an element. The build only finds attributes written directly on an element, so the AI assistant won't be able to edit the field.

Shown with undiscoveredEditables

WARNING in ⚠ editable discovery (markers-built-into-an-object)
{ "data-editable": "title" } sets data-editable on an object.
The build only reads data-editable where it's written on an element. The AI assistant won't be able to edit the field.
Fix, one of:
Write data-editable on the element:
data-editable="a-field"
If the object picks the channel or the key, declare what renders it:
defineEditableSource(YourEditable, { ... })
Before
export function PromoCard({ hasPersonalChannel }) {
const attributes = hasPersonalChannel ? { "data-editable": "card" } : { "data-companywide-editable": "card" };

return <div {...attributes}>Our offer</div>;
}
After: write it on the element
export function PromoCard() {
return <div data-editable="card">Our offer</div>;
}
After: declare what renders it
import { defineEditableSource, prop, resolveEditable } from "@livepreso/webpack-deck";

export function PromoCard(props) {
const { attrs } = resolveEditable(editable, props);

return <div {...attrs}>Our offer</div>;
}

const editable = defineEditableSource(PromoCard, {
everyone: { key: "{targetKey}-{id}-{instance}" },
personal: { when: prop("hasPersonalChannel"), key: "{targetKey}-{id}-{instance}" },
});

<PromoCard id="card" hasPersonalChannel />;

See:

description-without-a-field​

warningVanilla

You wrote a @public comment that isn't directly above a field. The comment only describes the element straight after it, even when a field sits inside that element, so the AI assistant isn't told what the field is for.

WARNING in ⚠ editable discovery (description-without-a-field)
"@public The badge shown beside a plan's name." isn't directly above a field.
A @public comment describes only the element straight after it, so the AI assistant isn't told what the field is for.
Fix, one of:
Move the comment directly above the element with the field.
Remove @public, if the comment doesn't describe a field.
Before
<!-- @public The badge shown beside a plan's name. -->
<span class="badge-wrap">
<img data-companywide-dynamic-image="plan-badge" />
</span>
After: move it above the field
<span class="badge-wrap">
<!-- @public The badge shown beside a plan's name. -->
<img data-companywide-dynamic-image="plan-badge" />
</span>
After: remove @public
<!-- The badge shown beside a plan's name. -->
<span class="badge-wrap">
<img data-companywide-dynamic-image="plan-badge" />
</span>

See:

description-written-twice​

warningReactVanilla

A description belongs to the key, not to whatever renders it, so exactly one line should carry it. Two that agree today are no better than two that differ: the next edit lands on one of them, and the one the build drops reads afterwards like a description nobody wrote.

WARNING in ⚠ editable discovery (description-written-twice)
Each key listed below is described on more than one line of the same slide, section or template. The AI assistant is told the first description the build reads, and the rest are dropped.
Fix: keep one description for each key, and delete the others.
Before
defineEditableSource(Headline, {
everyone: { key: "{targetKey}-{id}-{instance}" },
});

<Headline id="title" description="The plan's headline." />
<Headline id="title" description="Repeats the plan name." />
After
defineEditableSource(Headline, {
everyone: { key: "{targetKey}-{id}-{instance}" },
});

<Headline id="title" description="The plan's headline." />
<Headline id="title" />

See:

Project file​

keys-listed-twice​

warningReactVanilla

You list a key under editables: in project.yaml that the build also finds in your source. The build includes that key either way, so the entry in project.yaml does nothing. This warning lists every such key, grouped by slide, section or template.

WARNING in ⚠ editable discovery (keys-listed-twice)
title is listed under editables in project.yaml.
This key is discovered automatically, so it can be safely removed from the project file.
Fix: remove title from project.yaml.
Before
slides:
- key: plans
editables:
- title
After
slides:
- key: plans

keys-only-in-project-file​

warningReactVanilla

You list a key under editables: in project.yaml that the build doesn't find in your source. Either nothing uses the key any more, or your source builds it in a way the build can't read. This warning lists every such key, grouped by slide, section or template.

Shown with undiscoveredEditables

WARNING in ⚠ editable discovery (keys-only-in-project-file)
title-old is listed under editables in project.yaml, but it isn't discovered in your source.
Either nothing uses title-old any more, or your source builds it as an expression the build can't read.
Fix, one of:
Remove title-old from project.yaml, if nothing uses it.
Write title-old out in your source, or declare what renders it.
Before
slides:
- key: plans
editables:
- title-old
After: remove it, if nothing uses it
slides:
- key: plans
Before
export function Headline({ fieldKey }) {
return <p data-editable={fieldKey}>Our plans</p>;
}
After: write it out in your source
export function Headline() {
return <p data-editable="title-old">Our plans</p>;
}

Where the markup builds the key from content your deck authors, the keys are ones you know - they are the lines you wrote in project.yaml. Put that content in a module the build reads, declare what renders the field, and the lines come out of the project file.

A key built from a feed is the one shape with no answer. The rows arrive with the preso, so no list can name them, and the field is not registered. Where that is what you want, say so on the line and take the key out of project.yaml:

<!-- livepreso-ignore-next-line -->
<div data-companywide-dynamic-image="<%= badge.code %>"></div>

See Silencing a warning.

See:

defineEditableSource()​

Every warning here fails the build. None of the fields the declaration describes are registered.

declaration-not-written-out​

errorReactVanilla

The declaration has to be an object written at the call, because that is what the build reads the fields out of. A variable or a call only becomes an object when the deck runs, and the build reads your source without running it.

ERROR in ⚠ editable discovery (declaration-not-written-out)
Headline's declaration has to be an object written at the defineEditableSource call. The build cannot read a variable or a function call in its place, so Headline's fields would be missing for the AI assistant, and the build fails.
Fix, one of:
Write the object at the call. Spreading a const into it is fine:
defineEditableSource(YourEditable, { ...shared, everyone: { ... } })
Where a value differs at each place it is rendered, read it with prop():
personal: { when: prop("hasPersonalChannel"), key: "{id}" }
Before
const declaration = {
everyone: { key: "{targetKey}-{id}-{instance}" },
};

defineEditableSource(Headline, declaration);

A call in the same place is refused for the same reason:

Before: a call
defineEditableSource(Headline, buildDeclaration());

Inside the object, the ordinary rules for what the build can read apply, so spreading a const into it is fine:

A spread the build reads
const shared = { everyone: { key: "{targetKey}-{id}-{instance}" } };

defineEditableSource(Headline, { ...shared, type: "richtext" });
After: write the declaration out
defineEditableSource(Headline, {
everyone: { key: "{targetKey}-{id}-{instance}" },
});
After: read a per-usage value with prop()
defineEditableSource(Headline, {
everyone: { key: "{targetKey}-{id}-{instance}" },
personal: { when: prop("hasPersonalChannel"), key: "{targetKey}-{id}-{instance}" },
});

See:

declaration-has-no-name​

errorReactVanilla

You passed defineEditableSource something with no name, such as a class written in place. A declaration applies to what renders the field by its name, so none of its fields reach the AI assistant, and the build fails.

ERROR in ⚠ editable discovery (declaration-has-no-name)
class { ... } is passed to defineEditableSource as the thing that renders the field.
A declaration applies to what renders the field by its name, and this has none. Its fields would be missing for the AI assistant, so the build fails.
Fix: give it a name, and pass that name.
defineEditableSource(YourEditable, { ... })
Before
defineEditableSource(class { ... }, {
everyone: { key: "{targetKey}-{id}-{instance}" },
});
After
export class Headline { ... }

defineEditableSource(Headline, {
everyone: { key: "{targetKey}-{id}-{instance}" },
});

See:

declaration-has-no-channel​

errorReactVanilla

Your declaration doesn't specify a channel. A field needs an everyone or personal channel to save into, so none of its fields reach the AI assistant, and the build fails.

ERROR in ⚠ editable discovery (declaration-has-no-channel)
Headline's declaration doesn't specify a channel.
A field needs an everyone or personal channel to save what somebody types. Headline's fields would be missing for the AI assistant, so the build fails.
Fix, one of:
Add an everyone channel, shared by every preso made from the deck:
everyone: { key: "{targetKey}-{id}-{instance}" }
Add a personal channel, for one preso:
personal: { key: "{targetKey}-{id}-{instance}" }
Before
defineEditableSource(Headline, {
type: "text",
});
After: add an everyone channel
defineEditableSource(Headline, {
type: "text",
everyone: { key: "{targetKey}-{id}-{instance}" },
});
After: add a personal channel
defineEditableSource(Headline, {
type: "text",
personal: { key: "{targetKey}-{id}-{instance}" },
});

See:

channel-has-no-key​

errorReactVanilla

A channel in your declaration has no key. There's no default key, so its fields have nowhere to save, and the build fails. This covers the everyone and personal channels alike.

ERROR in ⚠ editable discovery (channel-has-no-key)
Headline's personal channel has no key.
A channel saves under the key you give it, and there's no default. Headline's fields would be missing for the AI assistant, so the build fails.
Fix: give the personal channel a key.
personal: { key: "{targetKey}-{id}-{instance}" }
Before: an everyone channel
defineEditableSource(Headline, {
everyone: {},
});
After
defineEditableSource(Headline, {
everyone: { key: "{targetKey}-{id}-{instance}" },
});
Before: a personal channel
defineEditableSource(Headline, {
personal: { when: prop("hasPersonalChannel") },
});
After
defineEditableSource(Headline, {
personal: { when: prop("hasPersonalChannel"), key: "{targetKey}-{id}-{instance}" },
});

See:

key-uses-an-unknown-placeholder​

errorReactVanilla

A key in your declaration uses a placeholder other than {targetKey}, {id} or {instance}. The build can't fill it in, so those fields cannot be saved, and the build fails. This covers a key on the everyone or personal channel, and a key in keyWhen.

ERROR in ⚠ editable discovery (key-uses-an-unknown-placeholder)
Headline's everyone channel builds its key from {slide}, which the build cannot fill in.
A placeholder can only be one of: {targetKey}, {id} or {instance}. Headline's fields would be missing for the AI assistant, so the build fails.
Fix: build the key from {targetKey}, {id} and {instance}.
everyone: { key: "{targetKey}-{id}-{instance}" },
Before: on the everyone channel
defineEditableSource(Headline, {
everyone: { key: "{slide}-{id}" },
});
After
defineEditableSource(Headline, {
everyone: { key: "{targetKey}-{id}-{instance}" },
});
Before: on the personal channel
defineEditableSource(Headline, {
personal: { key: "{slide}-{id}" },
});
After
defineEditableSource(Headline, {
personal: { key: "{targetKey}-{id}-{instance}" },
});
Before: in a keyWhen key
defineEditableSource(Headline, {
everyone: {
key: "{targetKey}-{id}-{instance}",
keyWhen: { shared: "{slide}" },
},
});
After
defineEditableSource(Headline, {
everyone: {
key: "{targetKey}-{id}-{instance}",
keyWhen: { shared: "{id}" },
},
});

See:

type-has-no-such-channel​

errorReactVanilla

You declared a video field with a personal channel. A video can only save to the everyone channel, so its fields don't reach the AI assistant, and the build fails.

ERROR in ⚠ editable discovery (type-has-no-such-channel)
PromoVideo is a video, and its declaration has a personal channel.
A video field can only save to the everyone channel. PromoVideo's fields would be missing for the AI assistant, so the build fails.
Fix: replace the personal channel with an everyone channel.
everyone: { key: "{targetKey}-{id}-{instance}" },
Before
defineEditableSource(PromoVideo, {
type: "video",
personal: { key: "{targetKey}-{id}-{instance}" },
});
After
defineEditableSource(PromoVideo, {
type: "video",
everyone: { key: "{targetKey}-{id}-{instance}" },
});

See:

prop-has-two-defaults​

errorReactVanilla

Two prop() calls read the same argument with different defaults. An argument can only have one default, so the build fails.

ERROR in ⚠ editable discovery (prop-has-two-defaults)
Headline's hasPersonalChannel argument has two different defaults.
An argument can only have one default. Headline's fields would be missing for the AI assistant, so the build fails.
Fix: pick one default, and give it in one prop() only.
prop("hasPersonalChannel", { default: false })
Before
defineEditableSource(Headline, {
props: {
prep: prop("hasPersonalChannel", { default: false }),
},
personal: {
when: prop("hasPersonalChannel", { default: true }),
key: "{targetKey}-{id}-{instance}",
},
});
After
defineEditableSource(Headline, {
props: {
prep: prop("hasPersonalChannel", { default: false }),
},
personal: {
when: prop("hasPersonalChannel"),
key: "{targetKey}-{id}-{instance}",
},
});

See:

field-option-outside-fields​

errorReactVanilla

You wrote id or description directly in a declaration, outside its fields object. Both must be declared inside a fields object, and the build fails until they are.

ERROR in ⚠ editable discovery (field-option-outside-fields)
Headline's declaration has id outside a fields object.
id and description must be declared inside a fields object. Headline's fields would be missing for the AI assistant, so the build fails.
Fix: move id into a fields object.
defineEditableSource(YourEditable, {
fields: { id: ... },
everyone: { ... },
})
Before
defineEditableSource(Headline, {
id: prop("idFromUsage"),
everyone: { key: "{targetKey}-{id}-{instance}" },
});
After
defineEditableSource(Headline, {
fields: { id: prop("idFromUsage") },
everyone: { key: "{targetKey}-{id}-{instance}" },
});

The same warning names description written outside fields:

Before
defineEditableSource(Headline, {
description: prop("whatItIsFor"),
everyone: { key: "{targetKey}-{id}-{instance}" },
});
After
defineEditableSource(Headline, {
fields: { description: prop("whatItIsFor") },
everyone: { key: "{targetKey}-{id}-{instance}" },
});

See:

fields-is-empty​

errorReactVanilla

Your declaration has an empty fields list. The build fails until the list names the fields it renders, or the declaration is removed.

ERROR in ⚠ editable discovery (fields-is-empty)
SlideHeader's declaration has an empty fields list, so the build fails.
Fix, one of:
List the fields YourEditable renders:
defineEditableSource(YourEditable, {
fields: [{ id: "a-field" }],
everyone: { ... },
})
Remove defineEditableSource, if YourEditable renders nothing editable.
Before
function SlideHeader() { ... }

defineEditableSource(SlideHeader, {
fields: [],
everyone: { key: "{targetKey}-{id}-{instance}" },
});
After: list the fields
function SlideHeader() { ... }

defineEditableSource(SlideHeader, {
fields: [{ id: "a-field" }],
everyone: { key: "{targetKey}-{id}-{instance}" },
});
After: remove the declaration
function SlideHeader() { ... }

See:

field-needs-a-unique-id​

errorReactVanilla

An entry in your declaration's fields list is missing its id, has an id that is something other than a string or prop(), or has the same id as another entry. The build fails until every entry has a unique id, and lists each entry that needs one.

ERROR in ⚠ editable discovery (field-needs-a-unique-id)
Each entry in SlideHeader's fields list needs a unique id. An id can only be a string or prop(). The build will fail unless every entry listed below has one.
Fix: give each entry listed below a unique id.
Before
function SlideHeader() { ... }

defineEditableSource(SlideHeader, {
fields: [
{ type: "image" },
{ id: 7 },
{ id: "a-third-field" },
{ id: "a-third-field", type: "image" },
],
everyone: { key: "{targetKey}-{id}-{instance}" },
});
After: give each entry a unique id
function SlideHeader() { ... }

defineEditableSource(SlideHeader, {
fields: [
{ id: "a-field", type: "image" },
{ id: "another-field" },
{ id: "a-third-field" },
{ id: "a-fourth-field", type: "image" },
],
everyone: { key: "{targetKey}-{id}-{instance}" },
});

See:

fields-without-an-id-key​

errorReactVanilla

A fields list names several fields from one declaration, so every channel's key has to be built from {id} to tell them apart. A key without {id} saves every entry under one key, so editing one changes them all.

ERROR in ⚠ editable discovery (fields-without-an-id-key)
SlideHeader's declaration has a fields list, so every key needs {id}. A key without {id} saves every field under one key, so editing one changes them all. The build will fail unless every key listed below has {id}.
Fix: add {id} to each key listed below.
Before
function SlideHeader() { ... }

defineEditableSource(SlideHeader, {
fields: [{ id: "a-field" }, { id: "another-field" }],
everyone: { key: "{targetKey}-header" },
personal: { key: "summary" },
});
After
function SlideHeader() { ... }

defineEditableSource(SlideHeader, {
fields: [{ id: "a-field" }, { id: "another-field" }],
everyone: { key: "{targetKey}-{id}-{instance}" },
personal: { key: "{targetKey}-{id}-{instance}" },
});

See:

declaration-rejected​

errorReactVanilla

A defineEditableSource call is missing something, or has something the build does not recognise. Each place below names the declaration and what was wrong with it, and the warning for that fault says how to fix it.

ERROR in ⚠ editable discovery (declaration-rejected)
The build refused each defineEditableSource call listed below, for the reason beside it, so its fields would be missing for the AI assistant and the build fails.
Fix: each reason below says what to change.
Before
defineEditableSource(Headline, {
type: "richy",
everyone: { key: "{targetKey}-{id}-{instance}" },
});
After
defineEditableSource(Headline, {
type: "richtext",
everyone: { key: "{targetKey}-{id}-{instance}" },
});

See:

Usages​

The examples in this section render these:

defineEditableSource(Headline, {
type: prop("kind", { default: "text" }),
everyone: { key: "{targetKey}-{id}-{instance}" },
personal: { when: prop("hasPersonalChannel"), key: "{targetKey}-{id}-{instance}" },
});

defineEditableSource(Disclaimer, {
everyone: { key: "{targetKey}-{id}-{instance}", scope: prop("scope", { default: "instance" }) },
});

defineEditableSource(PreparedFor, {
personal: { key: "{id}" },
});

defineEditableSource(Price, {
props: { currency: prop("currency") },
actions: price,
everyone: { key: "{targetKey}-{id}-{instance}" },
});

missing-id​

errorReactVanilla

A field is rendered with no id. Its key is built from the id, and the declaration gives the id no default, so there is no key to save it under, and the build fails.

ERROR in ⚠ editable discovery (missing-id)
Headline is rendered without an id. Its key is built from id, and its declaration doesn't give the id a default, so there's no key to save it under. The build will fail unless every place listed below has an id.
Fix: add an id to each place listed below.
Before
<Headline hasPersonalChannel />
After: add an id
<Headline id="title" hasPersonalChannel />

See:

unknown-field-type​

errorReactVanilla

A declaration reads its field type from an argument, and somewhere a field is rendered with a value that isn't text, richtext, image or video. The type decides which data-* attribute the field renders, so the build fails until every place uses one of those.

ERROR in ⚠ editable discovery (unknown-field-type)
Headline's declaration (src/Headline.js:40) reads its field type from kind. The type picks which data-* attribute Headline renders, so kind can only be text, richtext, image or video. The build will fail unless every place listed below uses one of those.
Fix: change kind at each place listed below to text, richtext, image or video.
Before
<Headline id="title" kind="rich" />
After: change the type
<Headline id="title" kind="richtext" />

See:

id-not-written-out​

warningReactVanilla

A field is rendered with its id written as an expression. The build reads your source without running the code, so the AI assistant won't be able to edit fields written that way.

Shown with undiscoveredEditables

WARNING in ⚠ editable discovery (id-not-written-out)
The build cannot read the id in <Headline id={plan.id} />, so the AI assistant won't be able to edit the fields listed below.
Fix, one of:
Write the id out as a string.
If the ids come from a list you know up front, list them in the declaration's fields.
If a function declared with defineEditableSource returns the ids, call it in this file and pass a property of the result: const ids = makeIds(); ... id={ids[name]}.
If a function passes on an id it was given, declare that function with defineEditableSource.
Before
<Headline id={makeId("title")} />
After: write the id out
<Headline id="title" />
Before
defineEditableSource(Headline, {
everyone: { key: "..." },
});

plans.map((plan) => <Headline id={plan.id} />);
After: list the ids in fields
defineEditableSource(Headline, {
fields: [{ id: "basic" }, { id: "premium" }],
everyone: { key: "..." },
});

plans.map((plan) => <Headline id={plan.id} />);
Before
function PlanTitle({ id }) {
return <Headline id={id} />;
}
After: declare the function passing it on
function PlanTitle({ id }) {
return <Headline id={id} />;
}

defineEditableSource(PlanTitle, { everyone: { ... } });
Before
function SectionBody({ ids, part }) {
return <Body id={ids[part]} />;
}
After: call the declared function that returns the ids
function SectionBody({ options, part }) {
const ids = sectionIds(options);

return <Body id={ids[part]} />;
}

Where a slide renders one field per row, the ids usually come from content your deck authors. Put that content in a module the build can read and the ids are known:

plans.js
export const PLANS = [{ id: "starter" }, { id: "growth" }, { id: "scale" }];
Headline.js
import { PLANS } from "./plans.js";

defineEditableSource(Headline, {
fields: PLANS,
everyone: { key: "{targetKey}-{id}" },
});

A key built from a feed is the one shape with no answer. The rows arrive with the preso, so no list can name them, and the field is not registered. Where that is what you want, say so on the line:

// livepreso-ignore-next-line id-not-written-out
<Badge id={badge.code} />

See Silencing a warning.

See:

unreadable-channel-argument​

warningReactVanilla

A channel can be switched on by an argument, with when: prop("..."). Where a field is rendered with a value the build cannot read, it cannot tell whether that field has the channel. This covers the everyone and personal channels alike.

Shown with undiscoveredEditables

WARNING in ⚠ editable discovery (unreadable-channel-argument)
The build cannot read hasPersonalChannel, so it treats every field listed below as having that channel. Where your deck leaves that channel unused, the AI assistant writes to a key the slide never shows. A user can still edit the field.
Fix, one of:
Write hasPersonalChannel out where it is passed.
Assign hasPersonalChannel to a const in this file, or import one, where the value is the same on every rendering.
Give prop() a default, where the value is decided while the slide runs.

Headline switches its personal channel on from hasPersonalChannel, so the two keys it can store under depend on what each rendering passes:

defineEditableSource(Headline, {
type: prop("kind", { default: "text" }),
everyone: { key: "{targetKey}-{id}-{instance}" },
personal: { when: prop("hasPersonalChannel"), key: "{targetKey}-{id}-{instance}" },
});

An everyone channel can be switched on the same way, and raises the same warning.

Before
<Headline id="title" hasPersonalChannel={canOverride()} />
After: write the argument out
<Headline id="title" hasPersonalChannel />
After: read it from a const
const canOverride = true;

<Headline id="title" hasPersonalChannel={canOverride} />;

A const works because the build follows it, in this file or one import away. A value decided while the slide runs needs a default on the argument instead, which goes in the declaration:

After: give the argument a default
defineEditableSource(Headline, {
type: prop("kind", { default: "text" }),
everyone: { key: "{targetKey}-{id}-{instance}" },
personal: {
when: prop("hasPersonalChannel", { default: true }),
key: "{targetKey}-{id}-{instance}",
},
});

The default says which channel the build registers. Where your deck does not use that channel, nothing is stored under that key and the AI assistant cannot edit the field. A user can still edit it.

See:

unreadable-key-choice​

warningReactVanilla

A keyWhen reads an argument to choose between two keys. Written as an expression, the build cannot read which of them your deck stores under, so it registers neither.

Shown with undiscoveredEditables

Where project.yaml still lists one of the two keys, the field works and this warns. Where it lists neither, what a user types is lost, so the build fails, and it is reported whether or not the flag is on.

WARNING in ⚠ editable discovery (unreadable-key-choice)
The build cannot read scope, so it cannot tell which of the two keys each field listed below is saved under. The AI assistant cannot edit them, and a line marked not saved loses what a user types into it.
Fix, one of:
Write the argument out where it is passed.
Give the argument a default, so one key always applies.
Declare what renders the field.

Disclaimer takes its scope from an argument, so the two keys it can store under are pricing-fees-{instance} and fees:

defineEditableSource(Disclaimer, {
everyone: { key: "{targetKey}-{id}-{instance}", scope: prop("scope", { default: "instance" }) },
});
Before
<Disclaimer id="fees" scope={readScope()} />
After: write the argument out
<Disclaimer id="fees" scope="deck" />

See:

arguments-spread​

warningReactVanilla

A field is rendered with an argument spread the build cannot read, such as {...props}, so it cannot tell whether an argument the declaration reads is inside it. A variable passed where a plain call takes its arguments, as in headline(options), is read the same way. For a function that returns ids, this shows only where no call on the slide can be read - see Ids from a declared function.

Shown with undiscoveredEditables

WARNING in ⚠ editable discovery (arguments-spread)
The build cannot read {...props}, so it cannot tell whether it carries the arguments Headline reads: id, kind and hasPersonalChannel. The AI assistant won't be able to edit the fields listed below.
Fix, one of:
Pass id, kind and hasPersonalChannel as separate arguments.
If a function passes on the arguments it was given, declare that function with defineEditableSource.
Before
function PlanCard(props) {
return <Headline {...props} />;
}
After: pass them as separate arguments
function PlanCard(props) {
return <Headline {...props} id="title" kind="text" hasPersonalChannel />;
}

The rendering stays as it is under this one. Declaring the function tells the build what the spread carries:

After: declare the function passing them on
function PlanCard(props) {
return <Headline {...props} />;
}

defineEditableSource(PlanCard, { everyone: { ... } });

See:

description-not-written-out​

warningReactVanilla

A field's description is written as an expression, so the build can't read what it says. The field still works; only the description is lost.

WARNING in ⚠ editable discovery (description-not-written-out)
The build cannot read the description in <Headline id="title" description={titleText} />, so the AI assistant won't know what the fields listed below are for. The fields still work.
Fix: write each description listed below out as a string.
Before
<Headline
id="title"
description={describe("title")}
/>
After: write the description out
<Headline
id="title"
description="The headline at the top of the slide."
/>

See:

toolbar-argument-not-written-out​

warningReactVanilla

A declaration reads its toolbar from an argument, and a field is rendered with that toolbar written as an expression. The build cannot read it, so the AI assistant won't be able to edit the field. It still works for a user.

WARNING in ⚠ editable discovery (toolbar-argument-not-written-out)
The build cannot read the toolbar in <Headline id="title" toolbar={pickToolbar("simple")} />, so the AI assistant won't be able to edit the fields listed below. The fields still work for a user.
Fix, one of:
Write each toolbar listed below out as a list of options.
Keep the variations in an object, and pass one by its property name, such as TOOLBARS.simple.
Before
<Headline
id="title"
toolbar={pickToolbar("simple")}
/>
After: write the toolbar out
<Headline
id="title"
toolbar={["bold", "italic"]}
/>
After: pick a variation by name
const TOOLBARS = {
simple: ["bold", "italic"],
full: ["style", "color", "list"],
};

<Headline id="title" toolbar={TOOLBARS.simple} />;

See:

copy-not-written-out​

warningReact

The text between a field's tags is what it shows before anybody edits it. The build cannot read children written as an expression, so the AI assistant won't know what the field starts as. The field still works for a user.

Shown with undiscoveredEditables

WARNING in ⚠ editable discovery (copy-not-written-out)
The build cannot read {plan.name}, so the AI assistant won't know what the fields listed below show before anyone edits them. The fields still work for a user.
Fix: write the children out as text, or as markup such as <b>Our plans</b>.

The build reads a const:

const PLAN = { name: "Growth" };

<Headline id="title">{PLAN.name}</Headline> // read
<Headline id="title">{readPlanName()}</Headline> // not read
Before
<Headline id="title" hasPersonalChannel>
{plan.name}
</Headline>
After: write the children out as text
<Headline id="title" hasPersonalChannel>
Our plans
</Headline>

Children built from a feed are the one shape with no answer. The rows arrive with the preso, so nothing in your source says what the field starts as. Where that is what you want, say so on the line:

{
/* livepreso-ignore-next-line copy-not-written-out */
}
<Headline id="title">{plan.name}</Headline>;

The AI assistant still won't know what the field starts as - see Silencing a warning.

See:

default-not-written-out​

warningReactVanilla

A declaration can take a field's starting copy from one of its arguments, so the copy lives at the place the field is rendered instead of between its tags. The build reads that argument the same way it reads children, and an expression it cannot read leaves the AI assistant with nothing to say the field starts as.

WARNING in ⚠ editable discovery (default-not-written-out)
Header's declaration takes its default copy from title, and the build cannot read what each place listed below passes. The AI assistant won't know what those fields show before anyone edits them. The fields still work for a user.
Fix, one of:
Write the value out where Header is rendered.
Pass a const or a .json key, which the build reads.
Give title a default in Header's declaration.

The build follows a const and a .json key, through as many files as the value passes:

import copy from "./copy.json";

<Header id="intro" title={copy.heading} /> // read
<Header id="intro" title={buildHeading()} /> // not read
Before
{
}
<Header id="intro" title={copy.heading[locale]} />;
After: pass a value the build reads
{
}
<Header id="intro" title={copy.heading} />;

See:

actions-prop-not-written-out​

warningReactVanilla

A declaration's actions read one of its arguments as a prop, and a field is rendered with that argument written as an expression. The build cannot read it, so the AI assistant won't know the value. The field still works for a user.

WARNING in ⚠ editable discovery (actions-prop-not-written-out)
The build cannot read currency={readCurrency()}, so the AI assistant won't know the currency that Price's actions read. The fields listed below still work for a user.
Fix: write each argument listed below out as a value.
Before
<Price id="monthly" currency={readCurrency()} />
After: write the argument out
<Price id="monthly" currency="AUD" />

See:

actions-prop-missing​

warningReactVanilla

A declaration's actions read one of its arguments as a prop, the declaration gives it no default, and a field is rendered without it. The AI assistant won't know the value. The field still works for a user.

WARNING in ⚠ editable discovery (actions-prop-missing)
Price's actions read currency, and Price's declaration doesn't give currency a default. The AI assistant won't know the value of currency for the fields listed below. The fields still work for a user.
Fix, one of:
Pass currency at each place listed below.
Give currency a default in Price's declaration.
Before
<Price id="monthly" />
After: pass the argument
<Price id="monthly" currency="AUD" />
After: give it a default
defineEditableSource(Price, {
props: { currency: prop("currency", { default: "AUD" }) },
actions: price,
everyone: { ... },
});

See:

defineActions()​

actions-value-not-readable​

errorReactVanilla

A declaration's actions has to be written out beside the component, so the build can copy it into the module the AI assistant calls. Given a function call or a variable, there is nothing written out to copy.

ERROR in ⚠ editable discovery (actions-value-not-readable)
actions has to be given your queries and mutations, or a const you assigned them to. The build will fail until each declaration listed below gives one of those.
Fix, one of:
Give actions your queries and mutations:
actions: { queries: { ... }, mutations: { ... } }
Give actions a const you assigned them to, here or imported:
actions: price
Before
defineEditableSource(Price, {
actions: buildActions(),
everyone: { key: "{targetKey}-{id}-{instance}" },
});
After
defineEditableSource(Price, {
actions: {
queries: { get: ({ state }) => state },
mutations: { set: ({ state, input }) => input },
},
everyone: { key: "{targetKey}-{id}-{instance}" },
});

See:

actions-not-written-out​

errorReactVanilla

defineActions reads its queries and mutations from the object written out inside the call. Given a variable, a function call or nothing, its queries and mutations would be missing for the AI assistant.

ERROR in ⚠ editable discovery (actions-not-written-out)
defineActions reads queries and mutations from an object written out inside it. Each defineActions listed below is given a variable, a function call or nothing, so its queries and mutations would be missing for the AI assistant. The build will fail until each one has its object written out.
Fix: write the object out inside each defineActions listed below.
defineActions({ queries: { ... }, mutations: { ... } })
Before
export const price = defineActions(
buildPriceActions(),
);
After: write the object out
export const price = defineActions({
defaultState: { amount: 0 },
queries: {
formatted: ({ state }) => state.amount,
},
});

See:

actions-use-an-unavailable-name​

errorReactVanilla

Actions written in the same file as what renders the field can use that file's imports, top-level consts and functions - everything except what renders the field itself. This warning names a top-level name the actions use that isn't one of those: a let or var, what renders the field, or a name the build can't follow.

ERROR in ⚠ editable discovery (actions-use-an-unavailable-name)
Actions written in the same file as what renders the field can use imports, top-level consts and functions, other than what renders the field. The build will fail until each name listed below is one of those.
Fix, one of:
Declare each name listed below with const, or as a function.
Move the actions into defineActions in a separate file, and import them.
Before
let TAX = 0.1;

defineEditableSource(Price, {
actions: {
queries: {
total: ({ state }) => state.amount * (1 + TAX),
},
},
everyone: { ... },
});
After: declare it with const
const TAX = 0.1;

defineEditableSource(Price, {
actions: {
queries: {
total: ({ state }) => state.amount * (1 + TAX),
},
},
everyone: { ... },
});
After: move the actions into a separate file
// price-actions.js
let TAX = 0.1;
export const price = defineActions({
queries: { total: ({ state }) => state.amount * (1 + TAX) },
});

// price.js
import { price } from "./price-actions.js";
defineEditableSource(Price, { actions: price, everyone: { ... } });

The same warning names what renders the field, where the actions read something off it. The actions are copied into a module the AI assistant calls with no slide open, and that module cannot reach back into the file it came from:

Before
function Price(props) { ... }
Price.currency = "USD";

defineEditableSource(Price, {
actions: {
queries: {
total: ({ state }) => `${Price.currency}${state.amount}`,
},
},
everyone: { ... },
});
After: take what the actions need out of the component
const CURRENCY = "USD";

function Price(props) { ... }

defineEditableSource(Price, {
actions: {
queries: {
total: ({ state }) => `${CURRENCY}${state.amount}`,
},
},
everyone: { ... },
});

Where the actions were reaching the component for something on the page, name rendered instead - see reaches-the-page.

See:

arguments-not-destructured​

errorReactVanilla

The build uses the names destructured in a query or mutation's parameter to decide where the AI assistant can use it. A parameter taken as one name instead, such as (args), can only be written destructured.

ERROR in ⚠ editable discovery (arguments-not-destructured)
The build uses the names destructured in a query or mutation's parameter, such as ({ state, input }), to decide where the AI assistant can use it. The parameter can only be written that way. The build will fail until each one listed below destructures its parameter.
Fix: destructure the parameter of each query or mutation listed below.
({ state, input }) => { ... }
Before
queries: {
formatted: (args) => args.state.amount,
},
After: destructure the parameter
queries: {
formatted: ({ state }) => state.amount,
},

See:

argument-not-used​

errorReactVanilla

The arguments a query or mutation names decide where it can be used. Naming cmsvals or feeds says it needs that value, so it is only offered where that value is supplied.

ERROR in ⚠ editable discovery (argument-not-used)
The arguments a query or mutation names decide where it can be used. The build will fail until each value listed below is used or removed.
Fix, one of:
Use the value in the body, if the query or mutation needs it.
Remove the value from the arguments.
To limit where the AI assistant can use a query or mutation, remove the value and name its channels:
yourQuery: { channels: ["everyone"], run: ({ state }) => { ... } }
Before
queries: {
formatted: ({ state, feeds }) => state.amount,
},
After: remove the name
queries: {
formatted: ({ state }) => state.amount,
},

See:

reaches-the-page​

errorReactVanilla

document, window and Bridge only exist while a slide is open, and the AI assistant can call a query or mutation with no slide open. A query or mutation that uses one of them directly can only run on the slide.

ERROR in ⚠ editable discovery (reaches-the-page)
document, window and Bridge only exist while a slide is open, and the AI assistant can call a query or mutation with no slide open. Each query or mutation listed below uses one of them. The build will fail until each one reads what it needs through rendered.
Fix: read what the slide shows through rendered, which the deck provides with provideRendered. For Bridge, provide a function that calls it.
({ rendered }) => rendered.yourElement.clientWidth
Before: price-actions.js
export const price = defineActions({
queries: {
width: () => document.querySelector(".price").clientWidth,
plans: () => Bridge.Feeds.read("plans"),
},
});
Before: Price.js
function Price(props) {
const { queries } = useActions(price, props);
return <span className="price">...</span>;
}
After: read it through rendered - price-actions.js
export const price = defineActions({
queries: {
width: ({ rendered }) => rendered.label.clientWidth,
plans: ({ rendered }) => rendered.loadPlans(),
},
});
After: read it through rendered - Price.js
function Price(props) {
const label = useRef(null);
const loadPlans = useRef(() => Bridge.Feeds.read("plans"));
const { queries } = useActions(price, props, { rendered: { label, loadPlans } });

return <span ref={label}>...</span>;
}

The slide hands over the element and a function that calls Bridge: in React through useActions()'s rendered option, which takes refs; in vanilla through provideRendered(). A query then reads both from rendered, and a call waits until the slide has provided them.

See:

doc-comment-above-run​

errorReactVanilla

In a query or mutation written as an object, with run inside it, the build reads the doc comment directly above run. A comment above the object is not read, so the AI assistant is told nothing about what it is for, and a mutation refuses every call that sends input.

ERROR in ⚠ editable discovery (doc-comment-above-run)
In a query or mutation written as an object, the doc comment goes directly above run. The build will fail until each comment listed below is there.
Fix: move each comment listed below directly above run.
yourMutation: {
/** What it does. @param ... */
run: ({ state, input }) => { ... },
},
Before
mutations: {
/**
* Change the price.
*
* @param {object} args
* @param {object} args.input
* @param {number} args.input.amount the new price
*/
set: {
channels: ["everyone"],
run: ({ state, input }) => {
state.amount = input.amount;
},
},
},
After: move the comment above run
mutations: {
set: {
channels: ["everyone"],
/**
* Change the price.
*
* @param {object} args
* @param {object} args.input
* @param {number} args.input.amount the new price
*/
run: ({ state, input }) => {
state.amount = input.amount;
},
},
},

See:

input-not-json​

errorReactVanilla

The AI assistant sends a query or mutation's input as JSON, which carries a string, number, boolean, array, plain object or null. There is no way to send a key typed as anything else, such as a Date or a function.

ERROR in ⚠ editable discovery (input-not-json)
mutations.set takes input.when as a Date.
The AI assistant sends input as JSON, which carries a string, number, boolean, array, plain object or null. There is no way to send a Date, so the build fails.
Fix, one of:
Give each key listed below one of those types.
Remove the key from the doc comment.
Before
/**
* @param {object} args
* @param {object} args.input
* @param {Date} args.input.when
*/
After: change the type
/**
* @param {object} args
* @param {object} args.input
* @param {string} args.input.when the date, as YYYY-MM-DD
*/

See:

input-not-described​

errorReactVanilla

A mutation's doc comment describes each value inside input, under the object the mutation receives. Two shapes miss it:

  • input described as the whole object. The mutation refuses every call that sends input.
  • input named on its own. The mutation takes any object the AI assistant sends.
ERROR in ⚠ editable discovery (input-not-described)
The comment describes the whole ({ state, input }) as input, so the build fails.
Fix: name the object first, then describe input inside it.
@param {object} args
@param {object} args.input
@param {number} args.input.amount the new price
Before
mutations: {
/**
* @param {object} input
*/
set: ({ state, input }) => {
state.amount = input.amount;
},

/**
* @param {object} args
* @param {object} args.input
*/
save: ({ state, input }) => { ... },
},
After: describe the values inside input
mutations: {
/**
* @param {object} args
* @param {object} args.input
* @param {number} args.input.amount the new price
*/
set: ({ state, input }) => {
state.amount = input.amount;
},

/**
* @param {object} args
* @param {object} args.input
* @param {number} args.input.amount the new price
*/
save: ({ state, input }) => { ... },
},
After: a .ts file describes them in the type of input
set: ({ input }: { input: { amount: number } }) => { ... },

See:

Silencing a warning​

livepreso-ignore-next-line​

Silences the warnings on the line below. Use it only where a value really is decided at runtime.

It silences the warning, not the problem. Everything the warning said the AI assistant would lose is still lost - a key it cannot read stays unregistered, and copy it cannot read stays unknown. What the comment buys is a build that stops telling you about a line you have already decided about.

// Every warning on the next line.
// livepreso-ignore-next-line
<Price id={plan.id} currency="AUD" />

// Only the warnings named.
// livepreso-ignore-next-line id-not-written-out, arguments-spread
<Price id={plan.id} {...plan} />
<!-- livepreso-ignore-next-line key-not-written-out -->

ignore-comment-does-nothing​

warningReactVanilla

A livepreso-ignore-next-line is above code that doesn't raise a warning.

WARNING in ⚠ editable discovery (ignore-comment-does-nothing)
Each livepreso-ignore-next-line listed below is above code that doesn't raise a warning.
Fix: delete each one listed below.
Before
{
}
{
/* livepreso-ignore-next-line */
}
<Headline id="title" hasPersonalChannel />;
After: delete it
<Headline id="title" hasPersonalChannel />

See:

ignore-comment-names-an-unknown-warning​

warningReactVanilla

A livepreso-ignore-next-line names a warning that doesn't exist.

WARNING in ⚠ editable discovery (ignore-comment-names-an-unknown-warning)
Each livepreso-ignore-next-line listed below names a warning that doesn't exist.
Fix, one of:
Correct the name to the one in the warning's heading.
Remove the name from the comment.
Before
{
}
{
/* livepreso-ignore-next-line id-not-writen-out */
}
<Price id={plan.id} currency="AUD" />;
After: correct the name
{
}
{
/* livepreso-ignore-next-line id-not-written-out */
}
<Price id={plan.id} currency="AUD" />;
After: remove the name
{
}
{
/* livepreso-ignore-next-line */
}
<Price id={plan.id} currency="AUD" />;

See:

showSilenced​

Lists every silenced warning on each build.

.deckrc.json
{
"warnings": { "showSilenced": true }
}
editable discovery (silenced)

2 warnings are silenced by a livepreso-ignore-next-line comment.

src/welcome.js:12:4 id-not-written-out
src/closing.js:30:8 arguments-spread