Establish cursor rules
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import React from "react";
|
||||
import InlineTextButton from "../../app/components/buttons/InlineTextButton";
|
||||
|
||||
export default {
|
||||
title: "Components/Buttons/InlineTextButton",
|
||||
component: InlineTextButton,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Small text-styled button for mid-paragraph 'link'-like controls (expand, add, …). Inherits parent typography and renders with a tertiary-colored underline. Use `Button` for primary/secondary actions.",
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
children: {
|
||||
control: { type: "text" },
|
||||
description: "Button label content.",
|
||||
},
|
||||
disabled: { control: { type: "boolean" } },
|
||||
ariaLabel: { control: { type: "text" } },
|
||||
onClick: { action: "clicked" },
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
args: {
|
||||
children: "Expand",
|
||||
},
|
||||
};
|
||||
|
||||
export const InParagraph = {
|
||||
render: () => (
|
||||
<p className="max-w-md font-inter text-[14px] leading-[20px] text-[color:var(--color-content-default-primary,#fff)]">
|
||||
Share a bit more detail so the group can weigh in. You can always{" "}
|
||||
<InlineTextButton onClick={() => {}}>expand this later</InlineTextButton>{" "}
|
||||
if you need more room.
|
||||
</p>
|
||||
),
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Typography is inherited from the parent, so the button sits naturally inside body copy.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled = {
|
||||
args: {
|
||||
children: "Expand",
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
import React from "react";
|
||||
import Incrementer from "../../app/components/controls/Incrementer";
|
||||
|
||||
export default {
|
||||
title: "Components/Controls/Incrementer",
|
||||
component: Incrementer,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Compact `[ - value + ]` row for numeric step input. Figma: `Control / Incrementer` (17857:30943). Pair with `IncrementerBlock` when you need a label above.",
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
value: {
|
||||
control: { type: "number" },
|
||||
description: "Current numeric value.",
|
||||
},
|
||||
min: {
|
||||
control: { type: "number" },
|
||||
description: "Minimum value (default -Infinity).",
|
||||
},
|
||||
max: {
|
||||
control: { type: "number" },
|
||||
description: "Maximum value (default Infinity).",
|
||||
},
|
||||
step: {
|
||||
control: { type: "number" },
|
||||
description: "Amount added/subtracted per click.",
|
||||
},
|
||||
disabled: {
|
||||
control: { type: "boolean" },
|
||||
description: "Disable both step buttons.",
|
||||
},
|
||||
onChange: { action: "change" },
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
render: (args) => {
|
||||
const [value, setValue] = React.useState(args.value ?? 50);
|
||||
return <Incrementer {...args} value={value} onChange={setValue} />;
|
||||
},
|
||||
args: {
|
||||
value: 50,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithBounds = {
|
||||
render: (args) => {
|
||||
const [value, setValue] = React.useState(50);
|
||||
return <Incrementer {...args} value={value} onChange={setValue} />;
|
||||
},
|
||||
args: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 10,
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Clamped to `min`/`max`; the corresponding step button auto-disables at the bounds.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const PercentageFormatter = {
|
||||
render: (args) => {
|
||||
const [value, setValue] = React.useState(75);
|
||||
return (
|
||||
<Incrementer
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
formatValue={(n) => `${n}%`}
|
||||
/>
|
||||
);
|
||||
},
|
||||
args: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 5,
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Use `formatValue` to render units alongside the number (e.g. `%`, `px`).",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled = {
|
||||
render: () => <Incrementer value={50} onChange={() => {}} disabled />,
|
||||
};
|
||||
@@ -0,0 +1,113 @@
|
||||
import React from "react";
|
||||
import IncrementerBlock from "../../app/components/controls/IncrementerBlock";
|
||||
|
||||
export default {
|
||||
title: "Components/Controls/IncrementerBlock",
|
||||
component: IncrementerBlock,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Labelled incrementer: pairs `InputLabel` with `Incrementer`. Figma: `Control / Incrementer Block` (19883:13283). Matches the grouped-field pattern used by `CheckboxGroup` / `RadioGroup`.",
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
label: {
|
||||
control: { type: "text" },
|
||||
description: "Label rendered above the incrementer.",
|
||||
},
|
||||
helpIcon: {
|
||||
control: { type: "boolean" },
|
||||
description: "Show the help (?) icon next to the label.",
|
||||
},
|
||||
asterisk: {
|
||||
control: { type: "boolean" },
|
||||
description: "Show an asterisk indicating a required field.",
|
||||
},
|
||||
helperText: {
|
||||
control: { type: "text" },
|
||||
description:
|
||||
"Helper text shown to the right of the label. Pass `true` to render the default 'Optional text'.",
|
||||
},
|
||||
labelSize: {
|
||||
control: { type: "select" },
|
||||
options: ["s", "m"],
|
||||
description: "Size of the label (Figma prop).",
|
||||
},
|
||||
palette: {
|
||||
control: { type: "select" },
|
||||
options: ["default", "inverse"],
|
||||
description: "Label palette.",
|
||||
},
|
||||
min: { control: { type: "number" } },
|
||||
max: { control: { type: "number" } },
|
||||
step: { control: { type: "number" } },
|
||||
disabled: { control: { type: "boolean" } },
|
||||
onChange: { action: "change" },
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
render: (args) => {
|
||||
const [value, setValue] = React.useState(args.value ?? 75);
|
||||
return <IncrementerBlock {...args} value={value} onChange={setValue} />;
|
||||
},
|
||||
args: {
|
||||
label: "Consensus level",
|
||||
helpIcon: true,
|
||||
value: 75,
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 5,
|
||||
},
|
||||
};
|
||||
|
||||
export const Required = {
|
||||
render: () => {
|
||||
const [value, setValue] = React.useState(50);
|
||||
return (
|
||||
<IncrementerBlock
|
||||
label="Quorum percentage"
|
||||
asterisk
|
||||
helperText="Required"
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
min={0}
|
||||
max={100}
|
||||
step={5}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const WithFormattedValue = {
|
||||
render: () => {
|
||||
const [value, setValue] = React.useState(75);
|
||||
return (
|
||||
<IncrementerBlock
|
||||
label="Consensus level"
|
||||
helperText="Optional"
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
min={0}
|
||||
max={100}
|
||||
step={5}
|
||||
formatValue={(n) => `${n}%`}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled = {
|
||||
render: () => (
|
||||
<IncrementerBlock
|
||||
label="Consensus level"
|
||||
value={75}
|
||||
onChange={() => {}}
|
||||
disabled
|
||||
/>
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
import React from "react";
|
||||
import ApplicableScopeField from "../../app/create/components/ApplicableScopeField";
|
||||
|
||||
export default {
|
||||
title: "Create Flow/ApplicableScopeField",
|
||||
component: ApplicableScopeField,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Shared 'Applicable Scope' field used by the `decision-approaches` and `conflict-management` create-flow modals. Pairs an `InputLabel` with a row of toggle-chips plus an inline pill input for adding new scope values.",
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
label: { control: { type: "text" } },
|
||||
addLabel: { control: { type: "text" } },
|
||||
inputPlaceholder: { control: { type: "text" } },
|
||||
onToggleScope: { action: "toggle" },
|
||||
onAddScope: { action: "add" },
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
};
|
||||
|
||||
const INITIAL_SCOPES = ["Finance", "Operations", "Product", "People"];
|
||||
|
||||
export const Default = {
|
||||
render: (args) => {
|
||||
const [scopes, setScopes] = React.useState(INITIAL_SCOPES);
|
||||
const [selected, setSelected] = React.useState(["Finance"]);
|
||||
|
||||
return (
|
||||
<div className="w-[520px]">
|
||||
<ApplicableScopeField
|
||||
{...args}
|
||||
scopes={scopes}
|
||||
selectedScopes={selected}
|
||||
onToggleScope={(scope) => {
|
||||
setSelected((prev) =>
|
||||
prev.includes(scope)
|
||||
? prev.filter((s) => s !== scope)
|
||||
: [...prev, scope],
|
||||
);
|
||||
}}
|
||||
onAddScope={(scope) => setScopes((prev) => [...prev, scope])}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
args: {
|
||||
label: "Applicable Scope",
|
||||
addLabel: "Add Applicable Scope",
|
||||
},
|
||||
};
|
||||
|
||||
export const Empty = {
|
||||
render: () => {
|
||||
const [scopes, setScopes] = React.useState([]);
|
||||
const [selected, setSelected] = React.useState([]);
|
||||
|
||||
return (
|
||||
<div className="w-[520px]">
|
||||
<ApplicableScopeField
|
||||
label="Applicable Scope"
|
||||
addLabel="Add Applicable Scope"
|
||||
scopes={scopes}
|
||||
selectedScopes={selected}
|
||||
onToggleScope={(scope) =>
|
||||
setSelected((prev) =>
|
||||
prev.includes(scope)
|
||||
? prev.filter((s) => s !== scope)
|
||||
: [...prev, scope],
|
||||
)
|
||||
}
|
||||
onAddScope={(scope) => setScopes((prev) => [...prev, scope])}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"With no scopes yet — only the '+ Add' affordance is visible. Click it to reveal the pill text input.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
import React from "react";
|
||||
import ModalTextAreaField from "../../app/create/components/ModalTextAreaField";
|
||||
|
||||
export default {
|
||||
title: "Create Flow/ModalTextAreaField",
|
||||
component: ModalTextAreaField,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Shared 'labelled text area' field used by every create-flow modal section. Pairs `InputLabel` (with help icon) with a `TextArea` set to the `embedded` appearance.",
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
label: { control: { type: "text" } },
|
||||
placeholder: { control: { type: "text" } },
|
||||
rows: { control: { type: "number" } },
|
||||
helpIcon: { control: { type: "boolean" } },
|
||||
disabled: { control: { type: "boolean" } },
|
||||
onChange: { action: "change" },
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
render: (args) => {
|
||||
const [value, setValue] = React.useState("");
|
||||
return (
|
||||
<div className="w-[520px]">
|
||||
<ModalTextAreaField {...args} value={value} onChange={setValue} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
args: {
|
||||
label: "Description",
|
||||
helpIcon: true,
|
||||
placeholder: "What does this rule cover?",
|
||||
rows: 4,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithValue = {
|
||||
render: () => {
|
||||
const [value, setValue] = React.useState(
|
||||
"We decide together whenever a change would affect more than two teams.",
|
||||
);
|
||||
return (
|
||||
<div className="w-[520px]">
|
||||
<ModalTextAreaField
|
||||
label="Core principle"
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled = {
|
||||
render: () => (
|
||||
<div className="w-[520px]">
|
||||
<ModalTextAreaField
|
||||
label="Description"
|
||||
value="Read-only content"
|
||||
onChange={() => {}}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
Reference in New Issue
Block a user