@marktiderman/genesis-forms-web 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,9 +6,9 @@ The web renderer for [Genesis Forms](../forms/README.md), built on Genesis UI co
6
6
  import { Form } from "@marktiderman/genesis-forms-web";
7
7
 
8
8
  <Form
9
- form={afterClass} // a defineForm result or a canonical definition
9
+ form={eventFeedback} // a defineForm result or a canonical definition
10
10
  layout="focus" // one question at a time; or "classic"
11
- options={{ hidden: { coach: "Sam" } }}
11
+ options={{ hidden: { owner: "Sam" } }}
12
12
  onChange={(state) => saveDraft(state)}
13
13
  onSubmit={(engine) => submit(engine.getState().events)}
14
14
  />
@@ -41,13 +41,13 @@ import { Form } from "@marktiderman/genesis-forms-web";
41
41
  `prefers-reduced-motion`). The ending is centred and large. In classic layout, page mode is one
42
42
  scrolling page, Google Forms style: a header card with the title and description, each question
43
43
  in its own card (red-edged while invalid), Submit at the end.
44
- `brand={{ name: "CrossFit Fairfield", logo }}` shows a practice's logo (an image URL or an
44
+ `brand={{ name: "Acme", logo }}` shows an organisation's or business's logo (an image URL or an
45
45
  element; its initials without one) and name small at the top of every step and on the ending.
46
46
  Custom slots and renderers can match with `useFormPresentation()`, which returns
47
47
  `{ presentation, layout }`.
48
48
 
49
49
  ```tsx
50
- <Form form={afterClass} presentation="page" brand={{ name: "CrossFit Fairfield" }} onSubmit={send} />
50
+ <Form form={eventFeedback} presentation="page" brand={{ name: "Acme" }} onSubmit={send} />
51
51
  ```
52
52
 
53
53
  - **Accessible by default:** group questions are a `fieldset` with a `legend`, and rating, NPS and
@@ -74,7 +74,27 @@ import { Form } from "@marktiderman/genesis-forms-web";
74
74
  `defaultRegistry.register(entry)` mutates the shared registry in place, for every form in the app.
75
75
 
76
76
  Renderers: short and long text, email, phone (`type="tel"`), rating, NPS, single choice, multiple
77
- choice, yes/no.
77
+ choice, yes/no, and the structured types:
78
+
79
+ - **`list`** (goals, action items, three wins) and **`table`** (an action plan with What / Who /
80
+ By when, pros and cons) add, remove and reorder entries (SortableList: drag, keyboard and a Move
81
+ menu).
82
+ - **`media-notes`** (lecture notes, reviewing a recorded call) takes a typed time (`m:ss`,
83
+ `h:mm:ss` or seconds). Wrap the form in `MediaTimeContext` to link it to your video or audio
84
+ player: `currentTime` prefills "Add note at 1:23" and `seek` plays from a note.
85
+ - **`text-highlights`** (annotating an article, a policy or a contract) takes highlights by
86
+ selecting words in the passage or typing them. The passage is the field's `text` prop, or the
87
+ value of `SourceTextContext` around the form.
88
+
89
+ ```tsx
90
+ <MediaTimeContext.Provider value={{ currentTime: () => player.currentTime, seek: (s) => player.seek(s) }}>
91
+ <SourceTextContext.Provider value={article.body}>
92
+ <Form form={videoNotes} onSubmit={send} />
93
+ </SourceTextContext.Provider>
94
+ </MediaTimeContext.Provider>
95
+ ```
96
+
97
+ `useMediaTime()` and `useSourceText()` read them in a custom renderer.
78
98
 
79
99
  ## License
80
100
 
package/dist/index.d.ts CHANGED
@@ -28,7 +28,7 @@ interface HeaderSlotProps {
28
28
  className?: string;
29
29
  }
30
30
  interface BrandSlotProps {
31
- /** The practice or business name, shown beside the logo. */
31
+ /** The organisation or business name, shown beside the logo. */
32
32
  name: string;
33
33
  /** An image URL or your own element. Without one, the name's initials are shown. */
34
34
  logo?: ReactNode;
@@ -110,7 +110,7 @@ interface FormProps {
110
110
  * layout the questions are sections on one scrolling page.
111
111
  */
112
112
  presentation?: FormPresentation | undefined;
113
- /** A practice's name and logo, shown small at the top of every step and on the ending. */
113
+ /** An organisation's or business's name and logo, shown small at the top of every step and on the ending. */
114
114
  brand?: FormBrand | undefined;
115
115
  registry?: RendererRegistry | undefined;
116
116
  /**
@@ -164,6 +164,7 @@ interface FieldChromeProps {
164
164
  */
165
165
  declare function FieldChrome({ props, children, className }: FieldChromeProps): react.JSX.Element;
166
166
  declare function describedBy(props: FieldRendererProps): string | undefined;
167
+
167
168
  declare const builtInRenderers: RendererEntry[];
168
169
  /**
169
170
  * The built-in web renderers, shared by every `<Form>` that gets no
@@ -172,4 +173,29 @@ declare const builtInRenderers: RendererEntry[];
172
173
  */
173
174
  declare const defaultRegistry: _marktiderman_genesis_forms_react.RendererRegistry;
174
175
 
175
- export { type BrandSlotProps, type EndingSlotProps, type ErrorSummaryItem, type ErrorSummarySlotProps, FieldChrome, type FieldChromeProps, Form, type FormBrand, type FormPresentation, type FormPresentationValue, type FormProps, type FormSlotMap, type HeaderSlotProps, type NavigationSlotProps, type ProgressSlotProps, builtInRenderers, defaultRegistry, describedBy, useFormPresentation };
176
+ /**
177
+ * The video or audio a form is about, as the host app plays it. `media-notes`
178
+ * fields read it: with `currentTime` the add row starts at the current moment
179
+ * ("Add note at 1:23"), with `seek` a note's time plays the media from there.
180
+ * Both are in seconds from the start of the full recording.
181
+ */
182
+ interface MediaTime {
183
+ /** The playhead now, or undefined when it isn't known yet. */
184
+ currentTime?: (() => number | undefined) | undefined;
185
+ /** Move the playhead. */
186
+ seek?: ((seconds: number) => void) | undefined;
187
+ }
188
+ /** Provide it around `<Form>` to link `media-notes` fields to a media player. */
189
+ declare const MediaTimeContext: react.Context<MediaTime | null>;
190
+ /** The enclosing `MediaTimeContext` value, or null. */
191
+ declare function useMediaTime(): MediaTime | null;
192
+ /**
193
+ * The text a form is about (an article, a policy, a contract). `text-highlights`
194
+ * fields highlight passages of it; a field's own `props.text` is used when no
195
+ * host provides one. Offsets are UTF-16 indices into this exact string.
196
+ */
197
+ declare const SourceTextContext: react.Context<string | null>;
198
+ /** The enclosing `SourceTextContext` value, or null. */
199
+ declare function useSourceText(): string | null;
200
+
201
+ export { type BrandSlotProps, type EndingSlotProps, type ErrorSummaryItem, type ErrorSummarySlotProps, FieldChrome, type FieldChromeProps, Form, type FormBrand, type FormPresentation, type FormPresentationValue, type FormProps, type FormSlotMap, type HeaderSlotProps, type MediaTime, MediaTimeContext, type NavigationSlotProps, type ProgressSlotProps, SourceTextContext, builtInRenderers, defaultRegistry, describedBy, useFormPresentation, useMediaTime, useSourceText };