forgebook 0.2.0 → 0.3.1

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.
Files changed (94) hide show
  1. package/README.md +113 -5
  2. package/dist/bin/forgebook/agentLoopCommands.mjs +3 -0
  3. package/dist/bin/forgebook/agentText.d.ts +2 -2
  4. package/dist/bin/forgebook/agentText.js +15 -13
  5. package/dist/bin/forgebook/agents.md +21 -6
  6. package/dist/bin/forgebook/mcpTools.js +1 -1
  7. package/dist/bin/forgebook/newStoriesFile.js +7 -2
  8. package/dist/bin/forgebook-docs/collectDocs.js +1 -1
  9. package/dist/src/argsProps.d.ts +32 -0
  10. package/dist/src/argsProps.js +69 -0
  11. package/dist/src/catalogue.d.ts +48 -5
  12. package/dist/src/catalogue.js +47 -8
  13. package/dist/src/frame/mountFrame.js +26 -7
  14. package/dist/src/frame/touchCaret.d.ts +43 -0
  15. package/dist/src/frame/touchCaret.js +195 -0
  16. package/dist/src/frame/touchEvents.d.ts +3 -2
  17. package/dist/src/frame/touchEvents.js +17 -18
  18. package/dist/src/frame/touchLayer.js +48 -7
  19. package/dist/src/propGroups.d.ts +66 -3
  20. package/dist/src/propGroups.js +67 -13
  21. package/dist/src/shell/ApiReference.d.ts +9 -4
  22. package/dist/src/shell/ApiReference.js +47 -39
  23. package/dist/src/shell/AudienceSections.js +1 -1
  24. package/dist/src/shell/ComponentPage.d.ts +5 -2
  25. package/dist/src/shell/ComponentPage.js +4 -18
  26. package/dist/src/shell/DocBlocks.js +1 -1
  27. package/dist/src/shell/PropRows.d.ts +42 -0
  28. package/dist/src/shell/PropRows.js +60 -0
  29. package/dist/src/shell/PropsTab.d.ts +14 -10
  30. package/dist/src/shell/PropsTab.js +18 -58
  31. package/dist/src/shell/RequiredFirstSwitch.d.ts +16 -0
  32. package/dist/src/shell/RequiredFirstSwitch.js +8 -0
  33. package/dist/src/shell/Stage.js +11 -23
  34. package/dist/src/shell/StoryCoverage.js +4 -1
  35. package/dist/src/shell/docPage.css +6 -0
  36. package/dist/src/shell/dockTabs.d.ts +7 -5
  37. package/dist/src/shell/dockTabs.js +4 -4
  38. package/dist/src/shell/reportedPanel.d.ts +12 -0
  39. package/dist/src/shell/reportedPanel.js +19 -0
  40. package/dist/src/shell/shell.css +56 -1
  41. package/dist/src/shell/strings.d.ts +2 -0
  42. package/dist/src/shell/strings.js +2 -0
  43. package/dist/src/shell/usePanelDocs.d.ts +11 -0
  44. package/dist/src/shell/usePanelDocs.js +29 -0
  45. package/dist/src/shell/useRequiredFirst.d.ts +27 -0
  46. package/dist/src/shell/useRequiredFirst.js +67 -0
  47. package/dist/src/storyCheck.d.ts +2 -0
  48. package/dist/src/storyCheck.js +2 -1
  49. package/dist/src/storyGlobals.js +2 -1
  50. package/dist/src/storyTree.d.ts +11 -1
  51. package/dist/src/storyTree.js +3 -1
  52. package/dist/src/viewState.d.ts +7 -0
  53. package/dist/src/viewState.js +13 -0
  54. package/dist/src/vite/agent.types.d.ts +12 -0
  55. package/dist/src/vite/agentApi.js +6 -1
  56. package/dist/src/vite/agentRoutes.js +18 -4
  57. package/dist/src/vite/builtTexts.d.ts +2 -2
  58. package/dist/src/vite/builtTexts.js +7 -6
  59. package/dist/src/vite/configFile.d.ts +3 -2
  60. package/dist/src/vite/configFile.js +63 -14
  61. package/dist/src/vite/docPagesModule.d.ts +10 -7
  62. package/dist/src/vite/docPagesModule.js +14 -11
  63. package/dist/src/vite/docsExtractor.d.ts +6 -0
  64. package/dist/src/vite/docsExtractor.js +13 -0
  65. package/dist/src/vite/fileAccess.d.ts +75 -0
  66. package/dist/src/vite/fileAccess.js +199 -0
  67. package/dist/src/vite/forgebookPlugin.d.ts +1 -1
  68. package/dist/src/vite/forgebookPlugin.js +67 -98
  69. package/dist/src/vite/framesServer.js +21 -5
  70. package/dist/src/vite/generatedModules.d.ts +23 -0
  71. package/dist/src/vite/generatedModules.js +58 -0
  72. package/dist/src/vite/hotSnippets.js +7 -3
  73. package/dist/src/vite/indexStoryFile.d.ts +2 -2
  74. package/dist/src/vite/indexStoryFile.js +2 -2
  75. package/dist/src/vite/indexedParameters.d.ts +1 -1
  76. package/dist/src/vite/indexedParameters.js +21 -1
  77. package/dist/src/vite/originGuard.d.ts +14 -4
  78. package/dist/src/vite/originGuard.js +15 -6
  79. package/dist/src/vite/pages.d.ts +3 -2
  80. package/dist/src/vite/pages.js +23 -16
  81. package/dist/src/vite/pluginIds.d.ts +24 -2
  82. package/dist/src/vite/pluginIds.js +44 -6
  83. package/dist/src/vite/pluginModules.d.ts +39 -10
  84. package/dist/src/vite/pluginModules.js +67 -22
  85. package/dist/src/vite/prebundled.js +2 -1
  86. package/dist/src/vite/searchModule.d.ts +6 -4
  87. package/dist/src/vite/searchModule.js +8 -7
  88. package/dist/src/vite/storyFilesModule.d.ts +59 -27
  89. package/dist/src/vite/storyFilesModule.js +88 -58
  90. package/dist/src/vite/storyPatterns.d.ts +39 -0
  91. package/dist/src/vite/storyPatterns.js +100 -0
  92. package/dist/src/vite/textQueries.d.ts +7 -1
  93. package/dist/src/vite/textQueries.js +7 -1
  94. package/package.json +4 -4
@@ -1,69 +1,27 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useId } from "react";
3
- import { isColorProp, isNamedProp, settableProps } from "../argTypes.js";
4
- import { isNamedArg } from "../messages.js";
5
- import { groupedProps, propGroupOrder } from "../propGroups.js";
2
+ import { isNamedProp, settableProps } from "../argTypes.js";
3
+ import { canOrderRequired, laidOutProps, propGroupOrder } from "../propGroups.js";
6
4
  import { useCatalogue } from "./catalogueContext.js";
7
5
  import { Icon } from "./icons.js";
8
- import { ChoiceControl, NumberField, textOf } from "./PropFields.js";
6
+ import { PropControl, ReadOnlyProp, Toggle } from "./PropRows.js";
7
+ import { RequiredFirstSwitch } from "./RequiredFirstSwitch.js";
9
8
  import { STRINGS } from "./strings.js";
10
- /** A CSS colour as the colour picker takes it (`#rrggbb`), or black when the value is not one. */
11
- const pickerColor = (value) => typeof value === "string" && /^#[0-9a-f]{6}$/i.test(value) ? value : "#000000";
9
+ import { useRequiredFirst } from "./useRequiredFirst.js";
12
10
  /** No prop named by a text key. */
13
11
  const NO_TEXT_ARGS = {};
14
12
  /** No group named first. */
15
13
  const NO_GROUPS = [];
16
- /** A prop's name, whether it is required, and its type (whole in the tooltip when it is cut). */
17
- const PropHead = ({ prop }) => (_jsxs("div", { className: "forgebook-prop__head", children: [_jsxs("code", { className: "forgebook-prop__name", children: [prop.label ?? prop.name, prop.isRequired ? (_jsx("span", { className: "forgebook-prop__required", title: STRINGS.required, children: "*" })) : null] }), _jsx("code", { className: "forgebook-prop__type", title: prop.type, children: prop.type })] }));
18
- /** A prop's description and default, under its control. */
19
- const PropNote = ({ id, prop }) => prop.description === "" && prop.defaultValue === undefined ? null : (_jsxs("p", { id: id, className: "forgebook-prop__description", children: [prop.description, prop.defaultValue === undefined ? null : (_jsxs(_Fragment, { children: [prop.description === "" ? null : " ", STRINGS.defaultIs, " ", _jsx("code", { children: prop.defaultValue })] }))] }));
20
- /**
21
- * Where a prop's text comes from, under its field: the key of the story's text, and a way back to it once the panel
22
- * wrote over it.
23
- *
24
- * @param props - the note, the prop's name and the value setter.
25
- */
26
- const TextArgLine = ({ note, name, onValueChange }) => (_jsxs("p", { className: "forgebook-prop__text-arg", children: [STRINGS.fromTexts, " ", _jsx("code", { children: note.key }), note.isChanged ? (_jsx("button", { type: "button", className: "forgebook-text-button", onClick: () => onValueChange(name, undefined), children: STRINGS.backToText })) : null] }));
27
- /** One adjustable prop with its control. */
28
- const PropControl = ({ prop, value, named, textArg, onValueChange }) => {
29
- // the description is shown under the control and named by it, so the control's name is the prop alone
30
- const descriptionId = useId();
31
- const label = prop.label ?? prop.name;
32
- if (named !== undefined) {
33
- return (_jsxs("div", { className: "forgebook-prop", children: [_jsx(PropHead, { prop: prop }), _jsxs("select", { "aria-label": label, "aria-describedby": descriptionId, value: isNamedArg(value) ? value.named : "", onChange: (event) => {
34
- const chosen = event.target.value;
35
- onValueChange(prop.name, chosen === "" ? undefined : { of: prop.type, named: chosen });
36
- }, children: [_jsx("option", { value: "", children: STRINGS.unset }), Object.keys(named).map((name) => (_jsx("option", { value: name, children: name }, name)))] }), _jsx(PropNote, { id: descriptionId, prop: prop })] }));
37
- }
38
- if (prop.kind === "choice") {
39
- return (_jsxs("div", { className: "forgebook-prop", children: [_jsx(PropHead, { prop: prop }), _jsx(ChoiceControl, { prop: prop, value: value, descriptionId: descriptionId, onValueChange: onValueChange }), _jsx(PropNote, { id: descriptionId, prop: prop })] }));
40
- }
41
- if (prop.kind === "number") {
42
- return (_jsxs("div", { className: "forgebook-prop", children: [_jsx(PropHead, { prop: prop }), _jsx("div", { className: "forgebook-prop__field", children: _jsx(NumberField, { prop: prop, value: value, descriptionId: descriptionId, onValueChange: onValueChange }) }), _jsx(PropNote, { id: descriptionId, prop: prop })] }));
43
- }
44
- return (_jsxs("div", { className: "forgebook-prop", children: [_jsx(PropHead, { prop: prop }), _jsxs("div", { className: "forgebook-prop__field", children: [_jsx("input", { type: "text", "aria-label": label, "aria-describedby": descriptionId, value: textOf(value), onChange: (event) => {
45
- const text = event.target.value;
46
- onValueChange(prop.name, text === "" ? undefined : text);
47
- } }), isColorProp(prop) ? (_jsx("input", { type: "color", className: "forgebook-prop__color", "aria-label": STRINGS.pickColor(label), value: pickerColor(value), onChange: (event) => onValueChange(prop.name, event.target.value) })) : null] }), textArg === undefined ? null : (_jsx(TextArgLine, { note: textArg, name: prop.name, onValueChange: onValueChange })), _jsx(PropNote, { id: descriptionId, prop: prop })] }));
48
- };
49
- /** A toggle: its name in a compact checkbox, its description as the tooltip and for screen readers. */
50
- const Toggle = ({ prop, value, onValueChange }) => {
51
- const descriptionId = useId();
52
- return (_jsxs("label", { className: "forgebook-toggle", title: prop.description, children: [_jsx("input", { type: "checkbox", checked: value === true, "aria-describedby": descriptionId, onChange: (event) => onValueChange(prop.name, event.target.checked) }), _jsx("code", { children: prop.label ?? prop.name }), _jsx("span", { id: descriptionId, className: "forgebook-visually-hidden", children: prop.description })] }));
53
- };
54
- /** A prop the panel cannot set: its name, its type and its description, for reading. */
55
- const ReadOnlyProp = ({ prop }) => (_jsxs("div", { className: "forgebook-prop", children: [_jsx(PropHead, { prop: prop }), _jsx("p", { className: "forgebook-prop__description", children: prop.description })] }));
56
14
  /**
57
15
  * A group the props' TSDoc names, under its name: its controls in the order of the props, its toggles, then the props
58
- * the panel cannot set.
16
+ * the panel cannot set. The "Required" group is drawn as one, each of its props naming its own group.
59
17
  *
60
- * @param props - the group's name and props, and how each prop is drawn.
18
+ * @param props - the group's name and props, how each prop is drawn, and whether it is the "Required" group.
61
19
  */
62
- const NamedGroup = ({ name, props, isSettable, control, toggle }) => {
20
+ const NamedGroup = ({ name, props, isSettable, control, toggle, isRequired = false }) => {
63
21
  const controls = props.filter((prop) => isSettable(prop) && prop.kind !== "toggle");
64
22
  const toggles = props.filter((prop) => isSettable(prop) && prop.kind === "toggle");
65
23
  const others = props.filter((prop) => !isSettable(prop));
66
- return (_jsx("div", { className: "forgebook-prop-group", children: _jsxs("details", { className: "forgebook-fold", open: true, children: [_jsxs("summary", { className: "forgebook-fold__summary forgebook-prop-group__title", children: [_jsx(Icon, { name: "chevronRight", size: 12 }), _jsx("h3", { className: "forgebook-fold__name", children: name }), _jsx("span", { className: "forgebook-fold__count", children: STRINGS.propCount(props.length) })] }), _jsxs("div", { className: "forgebook-prop-group__body", children: [controls.length === 0 ? null : _jsx("div", { className: "forgebook-prop-grid", children: controls.map(control) }), toggles.length === 0 ? null : _jsx("div", { className: "forgebook-toggles", children: toggles.map(toggle) }), others.length === 0 ? null : (_jsx("div", { className: "forgebook-prop-grid", children: others.map((prop) => (_jsx(ReadOnlyProp, { prop: prop }, prop.name))) }))] })] }) }));
24
+ return (_jsx("div", { className: "forgebook-prop-group", "data-required": isRequired || undefined, children: _jsxs("details", { className: "forgebook-fold", open: true, children: [_jsxs("summary", { className: "forgebook-fold__summary forgebook-prop-group__title", children: [_jsx(Icon, { name: "chevronRight", size: 12 }), _jsx("h3", { className: "forgebook-fold__name", children: name }), _jsx("span", { className: "forgebook-fold__count", children: STRINGS.propCount(props.length) })] }), _jsxs("div", { className: "forgebook-prop-group__body", children: [controls.length === 0 ? null : (_jsx("div", { className: "forgebook-prop-grid", children: controls.map((prop) => control(prop, isRequired)) })), toggles.length === 0 ? null : (_jsx("div", { className: "forgebook-toggles", children: toggles.map((prop) => toggle(prop, isRequired)) })), others.length === 0 ? null : (_jsx("div", { className: "forgebook-prop-grid", children: others.map((prop) => (_jsx(ReadOnlyProp, { prop: prop, showsGroup: isRequired }, prop.name))) }))] })] }) }));
67
25
  };
68
26
  /**
69
27
  * The worst case's button, and once it is on, how many elements spill (the frame outlines them).
@@ -76,17 +34,19 @@ const WorstCaseControl = ({ worstCase }) => (_jsxs(_Fragment, { children: [_jsx(
76
34
  *
77
35
  * @param props - the props, the values, which props the story lets the panel set, and the setters.
78
36
  */
79
- export const PropsTab = ({ props, values, controls, onValueChange, onReset, worstCase, namedValues = {}, textArgs = NO_TEXT_ARGS, componentGroups = NO_GROUPS }) => {
37
+ export const PropsTab = ({ props, values, controls, onValueChange, onReset, worstCase, namedValues = {}, textArgs = NO_TEXT_ARGS, componentGroups = NO_GROUPS, requiredFirst }) => {
80
38
  const catalogue = useCatalogue();
39
+ const ordering = useRequiredFirst(requiredFirst);
81
40
  const isNamed = (prop) => isNamedProp(prop, namedValues);
82
41
  const allSettable = settableProps(props, controls, namedValues);
83
42
  const isSettable = (prop) => allSettable.includes(prop);
84
- const propGroups = groupedProps(props.filter((prop) => prop.kind !== "event"), propGroupOrder(componentGroups, catalogue.propGroups));
85
- // the props that name no group are drawn as the tab always drew them, by control
43
+ const listed = props.filter((prop) => prop.kind !== "event");
44
+ const { required, groups: propGroups } = laidOutProps(listed, propGroupOrder(componentGroups, catalogue.propGroups), ordering.layout);
45
+ // the props that name no group are drawn as the tab always drew them, by control, in the layout's order
86
46
  const ungrouped = propGroups.find((group) => group.name === undefined)?.props ?? [];
87
- const settable = allSettable.filter((prop) => ungrouped.includes(prop));
88
- const control = (prop) => (_jsx(PropControl, { prop: prop, value: values[prop.name], named: isNamed(prop) ? namedValues[prop.type] : undefined, textArg: textArgs[prop.name], onValueChange: onValueChange }, prop.name));
89
- const toggle = (prop) => (_jsx(Toggle, { prop: prop, value: values[prop.name], onValueChange: onValueChange }, prop.name));
47
+ const settable = ungrouped.filter(isSettable);
48
+ const control = (prop, showsGroup) => (_jsx(PropControl, { prop: prop, showsGroup: showsGroup, value: values[prop.name], named: isNamed(prop) ? namedValues[prop.type] : undefined, textArg: textArgs[prop.name], onValueChange: onValueChange }, prop.name));
49
+ const toggle = (prop, showsGroup) => (_jsx(Toggle, { prop: prop, showsGroup: showsGroup, value: values[prop.name], onValueChange: onValueChange }, prop.name));
90
50
  const groups = [
91
51
  {
92
52
  title: STRINGS.propGroups.choice,
@@ -100,5 +60,5 @@ export const PropsTab = ({ props, values, controls, onValueChange, onReset, wors
100
60
  const toggles = settable.filter((prop) => prop.kind === "toggle");
101
61
  const others = ungrouped.filter((prop) => !isSettable(prop));
102
62
  const hasControls = controls === "all" || controls.length > 0;
103
- return (_jsxs("div", { className: "forgebook-tab-props", children: [hasControls ? null : _jsx("p", { className: "forgebook-tab-note", children: STRINGS.fixedExamples }), groups.map((group) => (_jsxs("div", { className: "forgebook-prop-group", children: [_jsx("h3", { className: "forgebook-prop-group__title", children: group.title }), _jsx("div", { className: "forgebook-prop-grid", children: group.props.map(control) })] }, group.title))), toggles.length === 0 ? null : (_jsxs("div", { className: "forgebook-prop-group", children: [_jsx("h3", { className: "forgebook-prop-group__title", children: STRINGS.propGroups.toggle }), _jsx("div", { className: "forgebook-toggles", children: toggles.map(toggle) })] })), others.length === 0 ? null : (_jsxs("div", { className: "forgebook-prop-group", children: [_jsx("h3", { className: "forgebook-prop-group__title", children: hasControls ? STRINGS.otherProps : STRINGS.allProps }), _jsx("div", { className: "forgebook-prop-grid", children: others.map((prop) => (_jsx(ReadOnlyProp, { prop: prop }, prop.name))) })] })), propGroups.map((group) => group.name === undefined ? null : (_jsx(NamedGroup, { name: group.name, props: group.props, isSettable: isSettable, control: control, toggle: toggle }, group.name))), hasControls ? (_jsxs("div", { className: "forgebook-tab-foot", children: [_jsx("button", { type: "button", className: "forgebook-text-button", onClick: onReset, children: STRINGS.resetArgs }), worstCase?.canApply === true ? _jsx(WorstCaseControl, { worstCase: worstCase }) : null] })) : null] }));
63
+ return (_jsxs("div", { className: "forgebook-tab-props", children: [canOrderRequired(listed) ? (_jsx("div", { className: "forgebook-tab-head", children: _jsx(RequiredFirstSwitch, { state: ordering }) })) : null, hasControls ? null : _jsx("p", { className: "forgebook-tab-note", children: STRINGS.fixedExamples }), required.length === 0 ? null : (_jsx(NamedGroup, { name: STRINGS.required, props: required, isSettable: isSettable, control: control, toggle: toggle, isRequired: true })), groups.map((group) => (_jsxs("div", { className: "forgebook-prop-group", children: [_jsx("h3", { className: "forgebook-prop-group__title", children: group.title }), _jsx("div", { className: "forgebook-prop-grid", children: group.props.map((prop) => control(prop, false)) })] }, group.title))), toggles.length === 0 ? null : (_jsxs("div", { className: "forgebook-prop-group", children: [_jsx("h3", { className: "forgebook-prop-group__title", children: STRINGS.propGroups.toggle }), _jsx("div", { className: "forgebook-toggles", children: toggles.map((prop) => toggle(prop, false)) })] })), others.length === 0 ? null : (_jsxs("div", { className: "forgebook-prop-group", children: [_jsx("h3", { className: "forgebook-prop-group__title", children: hasControls ? STRINGS.otherProps : STRINGS.allProps }), _jsx("div", { className: "forgebook-prop-grid", children: others.map((prop) => (_jsx(ReadOnlyProp, { prop: prop, showsGroup: false }, prop.name))) })] })), propGroups.map((group) => group.name === undefined ? null : (_jsx(NamedGroup, { name: group.name, props: group.props, isSettable: isSettable, control: control, toggle: toggle }, group.name))), hasControls ? (_jsxs("div", { className: "forgebook-tab-foot", children: [_jsx("button", { type: "button", className: "forgebook-text-button", onClick: onReset, children: STRINGS.resetArgs }), worstCase?.canApply === true ? _jsx(WorstCaseControl, { worstCase: worstCase }) : null] })) : null] }));
104
64
  };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The "Required first" switch in the header of a props table (the API reference, the Props tab): the reader turns the
3
+ * ordering of the required props on or off for every component (`useRequiredFirst.ts`).
4
+ *
5
+ * @module
6
+ */
7
+ import type { ReactNode } from "react";
8
+ import type { RequiredFirstState } from "./useRequiredFirst.ts";
9
+ /**
10
+ * The switch.
11
+ *
12
+ * @param props - its state, from `useRequiredFirst`.
13
+ */
14
+ export declare const RequiredFirstSwitch: ({ state }: {
15
+ readonly state: Pick<RequiredFirstState, "isOn" | "setIsOn">;
16
+ }) => ReactNode;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { STRINGS } from "./strings.js";
3
+ /**
4
+ * The switch.
5
+ *
6
+ * @param props - its state, from `useRequiredFirst`.
7
+ */
8
+ export const RequiredFirstSwitch = ({ state }) => (_jsxs("label", { className: "forgebook-required-first", title: STRINGS.requiredFirstHint, children: [_jsx("input", { type: "checkbox", role: "switch", "aria-checked": state.isOn, className: "forgebook-switch", checked: state.isOn, onChange: (event) => state.setIsOn(event.currentTarget.checked) }), STRINGS.requiredFirst] }));
@@ -15,7 +15,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
15
15
  import { panelProps, settableProps } from "../argTypes.js";
16
16
  import { matrixOf, matrixProps } from "../matrix.js";
17
17
  import { panelArgsParam, parsePanelArgsParam } from "../messages.js";
18
- import { NOT_FIXED, withFixed, withOwnFixed } from "../storyGlobals.js";
18
+ import { withFixed, withOwnFixed } from "../storyGlobals.js";
19
19
  import { frameAddress, isComparing, liveView, schemeOf, viewParams } from "../viewState.js";
20
20
  import { useStoryClockControls } from "./ClockControls.js";
21
21
  import { useCatalogue } from "./catalogueContext.js";
@@ -25,22 +25,21 @@ import { DroppedArgsNote } from "./DroppedArgsNote.js";
25
25
  import { dockTabs } from "./dockTabs.js";
26
26
  import { FrameView, tellFrames } from "./FrameView.js";
27
27
  import { framesOrigin } from "./framesOrigin.js";
28
+ import { reportedPanel } from "./reportedPanel.js";
28
29
  import { StageCompare } from "./StageCompare.js";
29
30
  import { StageTools } from "./StageTools.js";
30
31
  import { StageViewport } from "./StageViewport.js";
31
32
  import { StoryBar } from "./StoryBar.js";
32
33
  import { STRINGS } from "./strings.js";
33
34
  import { useAddressArgs } from "./useAddressArgs.js";
34
- import { useComponentDocs } from "./useComponentDocs.js";
35
35
  import { useFrameMessages } from "./useFrameMessages.js";
36
36
  import { useLiveView, useLoadedView } from "./useLiveView.js";
37
+ import { usePanelDocs } from "./usePanelDocs.js";
37
38
  import { usePluginStory, usePluginTabs } from "./usePluginTabs.js";
38
39
  import { useScrollMemory } from "./useScrollMemory.js";
39
40
  import { useStoryCheck } from "./useStoryCheck.js";
40
41
  import { useStoryCode } from "./useStoryCode.js";
41
42
  import { useWorstCase } from "./useWorstCase.js";
42
- /** The `argTypes` of a story before its frame reported them. */
43
- const NO_ARG_TYPES = {};
44
43
  /**
45
44
  * What the stage's handles set the width with; none, so no handles, when the story fixes the width.
46
45
  *
@@ -49,20 +48,6 @@ const NO_ARG_TYPES = {};
49
48
  * @param onViewChange - the view's setter.
50
49
  */
51
50
  const widthSetter = (fixed, view, onViewChange) => fixed.width === undefined ? (width) => onViewChange({ ...view, width }) : undefined;
52
- /**
53
- * A story's `argTypes`, controls, actions and fixed view for the panel and the stage: as its frame read them once it ran, which sees a setting
54
- * written by code the index leaves out; the index's controls and no `argTypes` or actions before.
55
- *
56
- * @param panels - what each story's frame reported, by story.
57
- * @param story - the story.
58
- */
59
- const reportedPanel = (panels, story) => panels.get(story.id) ?? {
60
- argTypes: NO_ARG_TYPES,
61
- controls: story.controls,
62
- actions: [],
63
- fixed: NOT_FIXED,
64
- parameters: []
65
- };
66
51
  /** The height of the first frame before its story reports its own, in CSS px. */
67
52
  const INITIAL_FRAME_HEIGHT = 240;
68
53
  /** The most calls the Events tab keeps. */
@@ -105,7 +90,6 @@ const embedHeight = (view, contentHeight, story) => view.height === "auto" ? Mat
105
90
  export const Stage = ({ component, story, view: ownView, onViewChange: onOwnViewChange, onFixedChange, panelArgs, onPanelArgsChange, matrixAxes, onMatrixAxesChange, frameUrl, plugins, loadCode, loadDocs, namedValues, header, onShownWidthChange, measuredHeight, backgroundOf, scroll }) => {
106
91
  const frameRef = useRef(null);
107
92
  const storyRef = useRef(null);
108
- const docs = useComponentDocs(loadDocs);
109
93
  const code = useStoryCode(loadCode);
110
94
  // the story's own args, as each frame reported them, by story
111
95
  const [storyArgs, setStoryArgs] = useState(new Map());
@@ -115,14 +99,17 @@ export const Stage = ({ component, story, view: ownView, onViewChange: onOwnView
115
99
  const [storyPanels, setStoryPanels] = useState(new Map());
116
100
  // the story is drawn with what it fixes of the view; a change from here keeps the user's own in the address
117
101
  const panel = reportedPanel(storyPanels, story);
118
- const view = withFixed(ownView, panel.fixed);
102
+ const catalogue = useCatalogue();
103
+ const docs = usePanelDocs(loadDocs, component.name, storyArgs.get(story.id), panel.actions);
104
+ // kept while neither changes: every new switches' object sends the frames the view, and a story whose height moves
105
+ // renders the stage at each report
106
+ const view = useMemo(() => withFixed(ownView, panel.fixed), [ownView, panel.fixed]);
119
107
  const onViewChange = (changed) => onOwnViewChange(withOwnFixed(changed, ownView, panel.fixed));
120
108
  const [calls, setCalls] = useState([]);
121
109
  // each story's play trace, by story: a trace belongs to the story that played
122
110
  const [traces, setTraces] = useState(new Map());
123
111
  // what each plugin's frame module last told its tab, by story: a plugin's report belongs to the story that sent it
124
112
  const [pluginReports, setPluginReports] = useState(new Map());
125
- const catalogue = useCatalogue();
126
113
  const { switches } = catalogue;
127
114
  const storyCheck = useStoryCheck(frameRef, frameAddress(frameUrl, story.id, view, switches));
128
115
  const eventNames = useMemo(() => docs.status === "ready"
@@ -192,6 +179,8 @@ export const Stage = ({ component, story, view: ownView, onViewChange: onOwnView
192
179
  onSpills: worstCase.receive,
193
180
  onPluginReport: (message) => setPluginReports((current) => new Map(current).set(`${message.storyId}|${message.plugin}`, message)),
194
181
  // a story that changes its own args changes the panel's values, as the reader would
182
+ // a story that could not be shown reports no args: the panel built from them has none, rather than waiting
183
+ onFailed: (storyId) => setStoryArgs((current) => (current.has(storyId) ? current : new Map(current).set(storyId, {}))),
195
184
  onStoryArgs: (storyId, args) => storyId === story.id ? onPanelArgsChange(args) : undefined
196
185
  });
197
186
  // the docs may arrive after the frames: they learn the events then
@@ -254,8 +243,7 @@ export const Stage = ({ component, story, view: ownView, onViewChange: onOwnView
254
243
  const tabs = dockTabs({
255
244
  docs,
256
245
  code,
257
- exportName: story.exportName,
258
- isLogic: story.isLogic,
246
+ story,
259
247
  componentName: component.name,
260
248
  argTypes: panel.argTypes,
261
249
  controls: panel.controls,
@@ -16,6 +16,7 @@ import { groupLabel } from "../catalogue.js";
16
16
  import { groupedStories } from "../storyTree.js";
17
17
  import { AUDIENCE_TEXTS } from "./audiencePage.js";
18
18
  import { CodeText } from "./CodeText.js";
19
+ import { useCatalogue } from "./catalogueContext.js";
19
20
  import { StoryLink } from "./Example.js";
20
21
  import { framesOrigin } from "./framesOrigin.js";
21
22
  import { a11yHint } from "./tabSummaries.js";
@@ -118,9 +119,11 @@ const checkText = (check) => {
118
119
  */
119
120
  export const StoryCoverage = ({ stories, storyGroups, queue, pageRef, settled, hrefOf, onOpen }) => {
120
121
  const { checks, checkAll } = usePageChecks(pageRef, queue, settled);
122
+ // a catalogue that checks no accessibility has no column for it, nor a check to run
123
+ const hasA11y = useCatalogue().a11y !== undefined;
121
124
  const ordered = groupedStories(stories, storyGroups.map((group) => group.id)).flatMap((section) => section.stories);
122
125
  const played = stories.filter((story) => story.hasPlay).length;
123
126
  const untested = stories.filter(isUntested).length;
124
127
  const finished = [...checks.values()].filter((check) => check.status !== "running").length;
125
- return (_jsxs("section", { className: "forgebook-doc__section", "aria-labelledby": "forgebook-coverage", children: [_jsx("h2", { id: "forgebook-coverage", children: AUDIENCE_TEXTS.coverage }), _jsxs("div", { className: "forgebook-coverage__head", children: [_jsx("p", { className: "forgebook-coverage__summary", children: AUDIENCE_TEXTS.coverageSummary(stories.length, played, untested) }), _jsx("button", { type: "button", className: "forgebook-button", onClick: checkAll, children: AUDIENCE_TEXTS.coverageCheckAll })] }), _jsx("p", { className: "forgebook-coverage__progress", role: "status", children: checks.size === 0 ? "" : AUDIENCE_TEXTS.coverageChecked(finished, stories.length) }), _jsx("div", { className: "forgebook-api", children: _jsxs("table", { className: "forgebook-api__table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: AUDIENCE_TEXTS.coverageStory }), _jsx("th", { scope: "col", children: AUDIENCE_TEXTS.coverageGroup }), _jsx("th", { scope: "col", children: AUDIENCE_TEXTS.coveragePlay }), _jsx("th", { scope: "col", children: AUDIENCE_TEXTS.coverageTests }), _jsx("th", { scope: "col", children: AUDIENCE_TEXTS.coverageA11y })] }) }), _jsx("tbody", { children: ordered.map((story) => (_jsxs("tr", { children: [_jsxs("th", { scope: "row", className: "forgebook-coverage__story", children: [_jsx(StoryLink, { story: story, hrefOf: hrefOf, onOpen: onOpen, className: "forgebook-link", children: story.name }), story.description === undefined ? null : (_jsx("span", { className: "forgebook-coverage__covers", children: _jsx(CodeText, { text: story.description }) }))] }), _jsx("td", { children: story.group === undefined ? "" : groupLabel(storyGroups, story.group) }), _jsx("td", { children: story.hasPlay ? AUDIENCE_TEXTS.coverageHasPlay : AUDIENCE_TEXTS.coverageNoPlay }), _jsx("td", { children: isUntested(story) ? AUDIENCE_TEXTS.coverageUntested : AUDIENCE_TEXTS.coverageTested }), _jsx("td", { children: checkText(checks.get(story.id)) })] }, story.id))) })] }) })] }));
128
+ return (_jsxs("section", { className: "forgebook-doc__section", "aria-labelledby": "forgebook-coverage", children: [_jsx("h2", { id: "forgebook-coverage", children: AUDIENCE_TEXTS.coverage }), _jsxs("div", { className: "forgebook-coverage__head", children: [_jsx("p", { className: "forgebook-coverage__summary", children: AUDIENCE_TEXTS.coverageSummary(stories.length, played, untested) }), hasA11y ? (_jsx("button", { type: "button", className: "forgebook-button", onClick: checkAll, children: AUDIENCE_TEXTS.coverageCheckAll })) : null] }), hasA11y ? (_jsx("p", { className: "forgebook-coverage__progress", role: "status", children: checks.size === 0 ? "" : AUDIENCE_TEXTS.coverageChecked(finished, stories.length) })) : null, _jsx("div", { className: "forgebook-api", children: _jsxs("table", { className: "forgebook-api__table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: AUDIENCE_TEXTS.coverageStory }), _jsx("th", { scope: "col", children: AUDIENCE_TEXTS.coverageGroup }), _jsx("th", { scope: "col", children: AUDIENCE_TEXTS.coveragePlay }), _jsx("th", { scope: "col", children: AUDIENCE_TEXTS.coverageTests }), hasA11y ? _jsx("th", { scope: "col", children: AUDIENCE_TEXTS.coverageA11y }) : null] }) }), _jsx("tbody", { children: ordered.map((story) => (_jsxs("tr", { children: [_jsxs("th", { scope: "row", className: "forgebook-coverage__story", children: [_jsx(StoryLink, { story: story, hrefOf: hrefOf, onOpen: onOpen, className: "forgebook-link", children: story.name }), story.description === undefined ? null : (_jsx("span", { className: "forgebook-coverage__covers", children: _jsx(CodeText, { text: story.description }) }))] }), _jsx("td", { children: story.group === undefined ? "" : groupLabel(storyGroups, story.group) }), _jsx("td", { children: story.hasPlay ? AUDIENCE_TEXTS.coverageHasPlay : AUDIENCE_TEXTS.coverageNoPlay }), _jsx("td", { children: isUntested(story) ? AUDIENCE_TEXTS.coverageUntested : AUDIENCE_TEXTS.coverageTested }), hasA11y ? _jsx("td", { children: checkText(checks.get(story.id)) }) : null] }, story.id))) })] }) })] }));
126
129
  };
@@ -168,6 +168,7 @@
168
168
  .forgebook-aside {
169
169
  --forgebook-tone: var(--forgebook-accent-text);
170
170
  display: grid;
171
+ grid-template-columns: minmax(0, 1fr);
171
172
  gap: 0.5rem;
172
173
  min-width: 0;
173
174
  margin: 0;
@@ -199,6 +200,7 @@
199
200
  }
200
201
  .forgebook-tabs {
201
202
  display: grid;
203
+ grid-template-columns: minmax(0, 1fr);
202
204
  gap: 0.75rem;
203
205
  min-width: 0;
204
206
  }
@@ -234,6 +236,7 @@
234
236
  }
235
237
  .forgebook-tabs__panel {
236
238
  display: grid;
239
+ grid-template-columns: minmax(0, 1fr);
237
240
  gap: 1rem;
238
241
  min-width: 0;
239
242
  }
@@ -242,6 +245,7 @@
242
245
  }
243
246
  .forgebook-steps {
244
247
  display: grid;
248
+ grid-template-columns: minmax(0, 1fr);
245
249
  gap: 1.25rem;
246
250
  margin: 0;
247
251
  padding: 0;
@@ -251,6 +255,7 @@
251
255
  .forgebook-steps__step {
252
256
  position: relative;
253
257
  display: grid;
258
+ grid-template-columns: minmax(0, 1fr);
254
259
  gap: 0.75rem;
255
260
  min-width: 0;
256
261
  padding-inline-start: calc(1.75rem + 0.75rem);
@@ -288,6 +293,7 @@
288
293
  }
289
294
  .forgebook-card {
290
295
  display: grid;
296
+ grid-template-columns: minmax(0, 1fr);
291
297
  align-content: start;
292
298
  gap: 0.5rem;
293
299
  min-width: 0;
@@ -16,9 +16,10 @@ import { type ComponentDocs } from "../componentDocs.ts";
16
16
  import type { ArgValue, PanelArgs } from "../messages.ts";
17
17
  import type { NamedValues } from "../namedValues.ts";
18
18
  import type { PlayTrace } from "../playTrace.ts";
19
+ import type { TreeStory } from "../storyTree.ts";
19
20
  import type { CheckState } from "./A11yTab.tsx";
20
21
  import type { DockTab } from "./Dock.tsx";
21
- import { type TextArgNote } from "./PropsTab.tsx";
22
+ import type { TextArgNote } from "./PropRows.tsx";
22
23
  import type { EventCall } from "./useFrameMessages.ts";
23
24
  import type { Loaded } from "./useLoaded.ts";
24
25
  import type { WorstCaseState } from "./worstArgs.ts";
@@ -28,10 +29,11 @@ export type DockTabsInput = {
28
29
  readonly docs: Loaded<ComponentDocs>;
29
30
  /** The story file's code, as loaded. */
30
31
  readonly code: Loaded<StoryFileCode>;
31
- /** The story's export name. */
32
- readonly exportName: string;
33
- /** Whether the story is about logic: its hook's signature comes first. */
34
- readonly isLogic: boolean;
32
+ /**
33
+ * The story: its export name, whether it is about logic (its hook's signature comes first), and where it puts the
34
+ * required props (none for the catalogue's).
35
+ */
36
+ readonly story: Pick<TreeStory, "exportName" | "isLogic" | "requiredFirst">;
35
37
  /** The component's name from the sidebar, for the JSX when the docs have none. */
36
38
  readonly componentName: string;
37
39
  /** The props the story lets the panel set. */
@@ -30,7 +30,7 @@ const propsTab = (input, props) => props.some((prop) => prop.kind !== "event")
30
30
  {
31
31
  id: "props",
32
32
  label: STRINGS.tabs.props,
33
- content: (_jsx(PropsTab, { props: props, values: input.values, controls: input.controls, onValueChange: input.onValueChange, onReset: input.onReset, worstCase: input.worstCase, namedValues: input.namedValues, textArgs: input.textArgs, componentGroups: input.propGroups }))
33
+ content: (_jsx(PropsTab, { props: props, values: input.values, controls: input.controls, onValueChange: input.onValueChange, onReset: input.onReset, worstCase: input.worstCase, namedValues: input.namedValues, textArgs: input.textArgs, componentGroups: input.propGroups, requiredFirst: input.story.requiredFirst }))
34
34
  }
35
35
  ]
36
36
  : [];
@@ -78,7 +78,7 @@ const docsTabs = (input) => {
78
78
  ];
79
79
  }
80
80
  // the docs' place while they load or fail: the tab the story opens on once they are read
81
- const docsTab = input.isLogic
81
+ const docsTab = input.story.isLogic
82
82
  ? { id: "signature", label: STRINGS.tabs.signature }
83
83
  : { id: "props", label: STRINGS.tabs.props };
84
84
  // the play's trace comes from the frame, not from the docs: a first read of a project's docs can take seconds, and a
@@ -91,7 +91,7 @@ const docsTabs = (input) => {
91
91
  }
92
92
  const component = docs.value;
93
93
  const events = eventsOf(component.props, input.actions);
94
- if (input.isLogic)
94
+ if (input.story.isLogic)
95
95
  return logicTabs(input, component);
96
96
  const tabs = [];
97
97
  tabs.push(...propsTab(input, panelProps(component.props, input.argTypes)));
@@ -158,7 +158,7 @@ const codeTabs = (input) => {
158
158
  label: STRINGS.tabs.code,
159
159
  content: (_jsx(LazyTab, { module: CODE_TAB, tabProps: {
160
160
  code: code.value,
161
- exportName: input.exportName,
161
+ exportName: input.story.exportName,
162
162
  componentName: docs.status === "ready" ? codeNameOf(docs.value) : input.componentName,
163
163
  args: input.values
164
164
  } }))
@@ -0,0 +1,12 @@
1
+ import type { TreeStory } from "../storyTree.ts";
2
+ import type { ReadyMessage } from "./useFrameMessages.ts";
3
+ /** What a story's frame reports for the panel and the stage. */
4
+ export type ReportedPanel = Pick<ReadyMessage, "argTypes" | "controls" | "actions" | "fixed" | "parameters">;
5
+ /**
6
+ * A story's `argTypes`, controls, actions and fixed view for the panel and the stage: as its frame read them once it ran, which sees a setting
7
+ * written by code the index leaves out; the index's controls and no `argTypes` or actions before.
8
+ *
9
+ * @param panels - what each story's frame reported, by story.
10
+ * @param story - the story.
11
+ */
12
+ export declare const reportedPanel: (panels: ReadonlyMap<string, ReportedPanel>, story: TreeStory) => ReportedPanel;
@@ -0,0 +1,19 @@
1
+ import { NOT_FIXED } from "../storyGlobals.js";
2
+ /** The `argTypes` of a story before its frame reported them. */
3
+ const NO_ARG_TYPES = {};
4
+ /** No actions, as one value: the panel's docs made from the args are kept while it stays the same. */
5
+ const NO_ACTIONS = [];
6
+ /**
7
+ * A story's `argTypes`, controls, actions and fixed view for the panel and the stage: as its frame read them once it ran, which sees a setting
8
+ * written by code the index leaves out; the index's controls and no `argTypes` or actions before.
9
+ *
10
+ * @param panels - what each story's frame reported, by story.
11
+ * @param story - the story.
12
+ */
13
+ export const reportedPanel = (panels, story) => panels.get(story.id) ?? {
14
+ argTypes: NO_ARG_TYPES,
15
+ controls: story.controls,
16
+ actions: NO_ACTIONS,
17
+ fixed: NOT_FIXED,
18
+ parameters: []
19
+ };
@@ -453,6 +453,7 @@
453
453
  }
454
454
  .forgebook-story {
455
455
  display: grid;
456
+ grid-template-columns: minmax(0, 1fr);
456
457
  gap: 0.625rem;
457
458
  margin: 1rem 2rem 2rem;
458
459
  min-width: 0;
@@ -464,6 +465,7 @@
464
465
  }
465
466
  .forgebook-story__bar {
466
467
  display: flex;
468
+ flex-wrap: wrap;
467
469
  align-items: center;
468
470
  gap: 0.5rem;
469
471
  }
@@ -598,6 +600,11 @@
598
600
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
599
601
  gap: 0.75rem 1.25rem;
600
602
  }
603
+ .forgebook-tab-head {
604
+ display: flex;
605
+ justify-content: flex-end;
606
+ padding: 0.625rem 0.875rem 0;
607
+ }
601
608
  .forgebook-tab-note {
602
609
  margin: 0;
603
610
  padding: 0.75rem 0.875rem 0;
@@ -1549,8 +1556,9 @@
1549
1556
  font: 400 0.6875rem/1.6 var(--forgebook-font-mono);
1550
1557
  }
1551
1558
  .forgebook-stage__heading {
1552
- flex: 1;
1559
+ flex: 1 1 10rem;
1553
1560
  display: grid;
1561
+ grid-template-columns: minmax(0, 1fr);
1554
1562
  gap: 0.125rem;
1555
1563
  min-width: 0;
1556
1564
  }
@@ -1559,6 +1567,7 @@
1559
1567
  font: 500 0.8125rem/1.35 var(--forgebook-font-sans);
1560
1568
  font-weight: 600;
1561
1569
  color: var(--forgebook-text);
1570
+ overflow-wrap: break-word;
1562
1571
  }
1563
1572
  .forgebook-stage__description {
1564
1573
  display: -webkit-box;
@@ -1622,6 +1631,7 @@
1622
1631
  }
1623
1632
  .forgebook-viewport {
1624
1633
  display: grid;
1634
+ grid-template-columns: minmax(0, 1fr);
1625
1635
  gap: 0.375rem;
1626
1636
  }
1627
1637
  .forgebook-viewport__canvas {
@@ -1726,15 +1736,18 @@
1726
1736
  .forgebook-home {
1727
1737
  box-sizing: border-box;
1728
1738
  display: grid;
1739
+ grid-template-columns: minmax(0, 1fr);
1729
1740
  gap: 1.5rem;
1730
1741
  width: 100%;
1731
1742
  max-width: 56rem;
1732
1743
  margin: 0 auto;
1733
1744
  padding: 1.5rem 2rem 2rem;
1745
+ overflow-wrap: break-word;
1734
1746
  animation: forgebook-rise 260ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
1735
1747
  }
1736
1748
  .forgebook-home__head {
1737
1749
  display: grid;
1750
+ grid-template-columns: minmax(0, 1fr);
1738
1751
  gap: 0.5rem;
1739
1752
  }
1740
1753
  .forgebook-home__title {
@@ -1766,6 +1779,7 @@
1766
1779
  }
1767
1780
  .forgebook-home__recent-link {
1768
1781
  display: grid;
1782
+ grid-template-columns: minmax(0, 1fr);
1769
1783
  gap: 0.125rem;
1770
1784
  padding: 0.5rem 0.75rem;
1771
1785
  border-radius: var(--forgebook-radius-control);
@@ -1805,6 +1819,7 @@
1805
1819
  }
1806
1820
  .forgebook-home__card {
1807
1821
  display: grid;
1822
+ grid-template-columns: minmax(0, 1fr);
1808
1823
  align-content: start;
1809
1824
  justify-items: start;
1810
1825
  gap: 0.5rem;
@@ -1821,6 +1836,7 @@
1821
1836
  width: 100%;
1822
1837
  margin: 0;
1823
1838
  font: 600 0.875rem/1.3 var(--forgebook-font-sans);
1839
+ overflow-wrap: anywhere;
1824
1840
  }
1825
1841
  .forgebook-home__count {
1826
1842
  font: 400 0.6875rem/1.35 var(--forgebook-font-sans);
@@ -1829,6 +1845,7 @@
1829
1845
  }
1830
1846
  .forgebook-home__components {
1831
1847
  display: grid;
1848
+ grid-template-columns: minmax(0, 1fr);
1832
1849
  gap: 0.25rem;
1833
1850
  margin: 0;
1834
1851
  padding: 0;
@@ -1903,6 +1920,7 @@
1903
1920
  }
1904
1921
  .forgebook-doc__section {
1905
1922
  display: grid;
1923
+ grid-template-columns: minmax(0, 1fr);
1906
1924
  gap: 1rem;
1907
1925
  }
1908
1926
  .forgebook-doc__section > h2 {
@@ -1916,6 +1934,7 @@
1916
1934
  }
1917
1935
  .forgebook-doc__group {
1918
1936
  display: grid;
1937
+ grid-template-columns: minmax(0, 1fr);
1919
1938
  gap: 1.5rem;
1920
1939
  }
1921
1940
  .forgebook-doc__group-name {
@@ -1938,10 +1957,12 @@
1938
1957
  }
1939
1958
  .forgebook-example {
1940
1959
  display: grid;
1960
+ grid-template-columns: minmax(0, 1fr);
1941
1961
  gap: 0.625rem;
1942
1962
  }
1943
1963
  .forgebook-example__head {
1944
1964
  display: grid;
1965
+ grid-template-columns: minmax(0, 1fr);
1945
1966
  gap: 0.25rem;
1946
1967
  }
1947
1968
  .forgebook-example__title {
@@ -2152,6 +2173,7 @@
2152
2173
  .forgebook-prose {
2153
2174
  font: 400 0.8125rem/1.4 var(--forgebook-font-sans);
2154
2175
  line-height: 1.6;
2176
+ overflow-wrap: break-word;
2155
2177
  }
2156
2178
  .forgebook-prose > :first-child {
2157
2179
  margin-top: 0;
@@ -2218,6 +2240,7 @@
2218
2240
  text-align: start;
2219
2241
  vertical-align: top;
2220
2242
  box-shadow: inset 0 -1px 0 var(--forgebook-separator);
2243
+ overflow-wrap: anywhere;
2221
2244
  }
2222
2245
  .forgebook-prose th {
2223
2246
  font-weight: 600;
@@ -2261,11 +2284,43 @@
2261
2284
  font-weight: 600;
2262
2285
  color: var(--forgebook-code-name);
2263
2286
  }
2287
+ .forgebook-api__head {
2288
+ display: flex;
2289
+ flex-wrap: wrap;
2290
+ align-items: center;
2291
+ justify-content: space-between;
2292
+ gap: 0.5rem 1rem;
2293
+ margin-top: 1rem;
2294
+ }
2295
+ .forgebook-api__head > h2 {
2296
+ margin: 0;
2297
+ font: 700 1.375rem/1.2 var(--forgebook-font-sans);
2298
+ }
2299
+ .forgebook-required-first {
2300
+ display: inline-flex;
2301
+ align-items: center;
2302
+ gap: 0.375rem;
2303
+ font: 400 0.6875rem/1.35 var(--forgebook-font-sans);
2304
+ font-weight: 500;
2305
+ color: var(--forgebook-text-secondary);
2306
+ cursor: pointer;
2307
+ }
2308
+ .forgebook-prop__group {
2309
+ margin-inline: 0.375rem auto;
2310
+ padding: 0 0.375rem;
2311
+ border-radius: 999px;
2312
+ background: var(--forgebook-fill);
2313
+ font: 400 0.6875rem/1.35 var(--forgebook-font-sans);
2314
+ font-weight: 400;
2315
+ color: var(--forgebook-text-secondary);
2316
+ white-space: nowrap;
2317
+ }
2264
2318
  .forgebook-api__type {
2265
2319
  min-width: 10rem;
2266
2320
  }
2267
2321
  .forgebook-api__subcomponent {
2268
2322
  display: grid;
2323
+ grid-template-columns: minmax(0, 1fr);
2269
2324
  gap: 0.75rem;
2270
2325
  margin-top: 1rem;
2271
2326
  }
@@ -160,6 +160,8 @@ declare const shellStrings: {
160
160
  rangeValue: (prop: string) => string;
161
161
  setByStory: string;
162
162
  required: string;
163
+ requiredFirst: string;
164
+ requiredFirstHint: string;
163
165
  resetArgs: string;
164
166
  appearance: string;
165
167
  appearanceOf: (name: string) => string;
@@ -127,6 +127,8 @@ const shellStrings = {
127
127
  rangeValue: (prop) => `${prop}: value`,
128
128
  setByStory: "Set by the story",
129
129
  required: "Required",
130
+ requiredFirst: "Required first",
131
+ requiredFirstHint: "Every component's required props before the others; kept in this browser",
130
132
  resetArgs: "Reset",
131
133
  appearance: "Appearance",
132
134
  appearanceOf: (name) => `Appearance: ${name}`,