@charcuterie/ui 2.18.0 → 3.1.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 +10 -0
- package/dist/Badge/Badge.d.ts +33 -3
- package/dist/Badge/Badge.d.ts.map +1 -1
- package/dist/Badge/Badge.js +20 -2
- package/dist/Badge/Badge.js.map +1 -1
- package/dist/Board/Board.d.ts +119 -0
- package/dist/Board/Board.d.ts.map +1 -0
- package/dist/Board/Board.js +165 -0
- package/dist/Board/Board.js.map +1 -0
- package/dist/Board/BoardCard.d.ts +120 -0
- package/dist/Board/BoardCard.d.ts.map +1 -0
- package/dist/Board/BoardCard.js +77 -0
- package/dist/Board/BoardCard.js.map +1 -0
- package/dist/Board/BoardLaneList.d.ts +103 -0
- package/dist/Board/BoardLaneList.d.ts.map +1 -0
- package/dist/Board/BoardLaneList.js +69 -0
- package/dist/Board/BoardLaneList.js.map +1 -0
- package/dist/Board/boardMove.d.ts +116 -0
- package/dist/Board/boardMove.d.ts.map +1 -0
- package/dist/Board/boardMove.js +116 -0
- package/dist/Board/boardMove.js.map +1 -0
- package/dist/Board/useBoardDrag.d.ts +44 -0
- package/dist/Board/useBoardDrag.d.ts.map +1 -0
- package/dist/Board/useBoardDrag.js +237 -0
- package/dist/Board/useBoardDrag.js.map +1 -0
- package/dist/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/Checkbox/Checkbox.js +15 -4
- package/dist/Checkbox/Checkbox.js.map +1 -1
- package/dist/DataTable/DataTable.d.ts +159 -0
- package/dist/DataTable/DataTable.d.ts.map +1 -0
- package/dist/DataTable/DataTable.js +197 -0
- package/dist/DataTable/DataTable.js.map +1 -0
- package/dist/DatePicker/DateGrid.d.ts +79 -0
- package/dist/DatePicker/DateGrid.d.ts.map +1 -0
- package/dist/DatePicker/DateGrid.js +220 -0
- package/dist/DatePicker/DateGrid.js.map +1 -0
- package/dist/DatePicker/DatePicker.d.ts +138 -0
- package/dist/DatePicker/DatePicker.d.ts.map +1 -0
- package/dist/DatePicker/DatePicker.js +384 -0
- package/dist/DatePicker/DatePicker.js.map +1 -0
- package/dist/DatePicker/datePresets.d.ts +29 -0
- package/dist/DatePicker/datePresets.d.ts.map +1 -0
- package/dist/DatePicker/datePresets.js +28 -0
- package/dist/DatePicker/datePresets.js.map +1 -0
- package/dist/DatePicker/parseDateInput.d.ts +106 -0
- package/dist/DatePicker/parseDateInput.d.ts.map +1 -0
- package/dist/DatePicker/parseDateInput.js +419 -0
- package/dist/DatePicker/parseDateInput.js.map +1 -0
- package/dist/DatePicker/plainDate.d.ts +167 -0
- package/dist/DatePicker/plainDate.d.ts.map +1 -0
- package/dist/DatePicker/plainDate.js +272 -0
- package/dist/DatePicker/plainDate.js.map +1 -0
- package/dist/MarkdownEditor/MarkdownEditor.d.ts +147 -0
- package/dist/MarkdownEditor/MarkdownEditor.d.ts.map +1 -0
- package/dist/MarkdownEditor/MarkdownEditor.js +492 -0
- package/dist/MarkdownEditor/MarkdownEditor.js.map +1 -0
- package/dist/MarkdownEditor/markdownCommands.d.ts +202 -0
- package/dist/MarkdownEditor/markdownCommands.d.ts.map +1 -0
- package/dist/MarkdownEditor/markdownCommands.js +379 -0
- package/dist/MarkdownEditor/markdownCommands.js.map +1 -0
- package/dist/MarkdownEditor/markdownSpans.d.ts +92 -0
- package/dist/MarkdownEditor/markdownSpans.d.ts.map +1 -0
- package/dist/MarkdownEditor/markdownSpans.js +303 -0
- package/dist/MarkdownEditor/markdownSpans.js.map +1 -0
- package/dist/Select/Select.d.ts +36 -1
- package/dist/Select/Select.d.ts.map +1 -1
- package/dist/Select/Select.js +38 -2
- package/dist/Select/Select.js.map +1 -1
- package/dist/categoricalStyles.d.ts +53 -0
- package/dist/categoricalStyles.d.ts.map +1 -0
- package/dist/categoricalStyles.js +195 -0
- package/dist/categoricalStyles.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/Badge/Badge.mdx +46 -0
- package/src/Badge/Badge.stories.tsx +98 -4
- package/src/Badge/Badge.test.tsx +157 -2
- package/src/Badge/Badge.tsx +49 -3
- package/src/Board/Board.mdx +199 -0
- package/src/Board/Board.stories.tsx +707 -0
- package/src/Board/Board.test.tsx +310 -0
- package/src/Board/Board.tsx +333 -0
- package/src/Board/BoardCard.tsx +290 -0
- package/src/Board/BoardLaneList.tsx +275 -0
- package/src/Board/boardMove.test.ts +213 -0
- package/src/Board/boardMove.ts +225 -0
- package/src/Board/useBoardDrag.ts +413 -0
- package/src/Checkbox/Checkbox.tsx +34 -3
- package/src/DataTable/DataTable.mdx +123 -0
- package/src/DataTable/DataTable.stories.tsx +411 -0
- package/src/DataTable/DataTable.test.tsx +386 -0
- package/src/DataTable/DataTable.tsx +497 -0
- package/src/DatePicker/DateGrid.tsx +467 -0
- package/src/DatePicker/DatePicker.mdx +170 -0
- package/src/DatePicker/DatePicker.stories.tsx +268 -0
- package/src/DatePicker/DatePicker.test.tsx +455 -0
- package/src/DatePicker/DatePicker.tsx +852 -0
- package/src/DatePicker/datePresets.ts +34 -0
- package/src/DatePicker/parseDateInput.test.ts +187 -0
- package/src/DatePicker/parseDateInput.ts +629 -0
- package/src/DatePicker/plainDate.test.ts +375 -0
- package/src/DatePicker/plainDate.ts +465 -0
- package/src/MarkdownEditor/MarkdownEditor.mdx +189 -0
- package/src/MarkdownEditor/MarkdownEditor.stories.tsx +267 -0
- package/src/MarkdownEditor/MarkdownEditor.test.tsx +627 -0
- package/src/MarkdownEditor/MarkdownEditor.tsx +862 -0
- package/src/MarkdownEditor/markdownCommands.test.ts +384 -0
- package/src/MarkdownEditor/markdownCommands.ts +566 -0
- package/src/MarkdownEditor/markdownSpans.test.ts +217 -0
- package/src/MarkdownEditor/markdownSpans.ts +458 -0
- package/src/Select/Select.mdx +44 -0
- package/src/Select/Select.stories.tsx +55 -0
- package/src/Select/Select.test.tsx +89 -1
- package/src/Select/Select.tsx +58 -2
- package/src/argTypes.storyHelpers.ts +39 -0
- package/src/categoricalStyles.ts +244 -0
- package/src/index.ts +89 -0
- package/src/sourceRules.test.ts +52 -1
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import { useState } from "react"
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
ContainerBoard,
|
|
6
|
+
StoryCell,
|
|
7
|
+
StoryGrid,
|
|
8
|
+
} from "../board.storyHelpers.tsx"
|
|
9
|
+
import { Field } from "../Field/Field.tsx"
|
|
10
|
+
import { MarkdownEditor } from "./MarkdownEditor.tsx"
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Invented, like every fixture in this repo. A task in a made-up
|
|
14
|
+
* homelab project, exercising each construct the painted layer
|
|
15
|
+
* knows about.
|
|
16
|
+
*/
|
|
17
|
+
const SAMPLE = `## Rack move, phase two
|
|
18
|
+
|
|
19
|
+
The **short** version: pull the _old_ switch, land the new one, and
|
|
20
|
+
keep the ~~three~~ two uplinks live throughout.
|
|
21
|
+
|
|
22
|
+
- [x] Label every patch lead
|
|
23
|
+
- [ ] Photograph the current cabling
|
|
24
|
+
- [ ] Cut over at 02:00
|
|
25
|
+
|
|
26
|
+
1. Power down the shelf
|
|
27
|
+
2. Swap the rails
|
|
28
|
+
3. Bring it back up
|
|
29
|
+
|
|
30
|
+
> Nothing here touches the storage pool.
|
|
31
|
+
|
|
32
|
+
Run \`ping -c 3 gateway.invalid\` before and after, and read
|
|
33
|
+
[the runbook](https://example.invalid/runbook) first.
|
|
34
|
+
|
|
35
|
+
| Port | Goes to |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| 1 | uplink |
|
|
38
|
+
| 2 | shelf |
|
|
39
|
+
|
|
40
|
+
\`\`\`sh
|
|
41
|
+
ip -br addr show
|
|
42
|
+
\`\`\`
|
|
43
|
+
`
|
|
44
|
+
|
|
45
|
+
const noop = () => undefined
|
|
46
|
+
|
|
47
|
+
const meta = {
|
|
48
|
+
title: "Components/MarkdownEditor",
|
|
49
|
+
component: MarkdownEditor,
|
|
50
|
+
parameters: { layout: "padded" },
|
|
51
|
+
args: {
|
|
52
|
+
isDisabled: false,
|
|
53
|
+
isReadOnly: false,
|
|
54
|
+
label: "Description",
|
|
55
|
+
placeholder: "Write it in markdown…",
|
|
56
|
+
},
|
|
57
|
+
} satisfies Meta<typeof MarkdownEditor>
|
|
58
|
+
|
|
59
|
+
export default meta
|
|
60
|
+
|
|
61
|
+
type Story = StoryObj<typeof meta>
|
|
62
|
+
|
|
63
|
+
export const Default: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
defaultValue: SAMPLE,
|
|
66
|
+
label: "Description",
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const AllVariants: Story = {
|
|
71
|
+
args: { label: "Description" },
|
|
72
|
+
render: () => (
|
|
73
|
+
<StoryGrid columns={2}>
|
|
74
|
+
<StoryCell align="stretch" label="empty">
|
|
75
|
+
<MarkdownEditor
|
|
76
|
+
label="Empty description"
|
|
77
|
+
placeholder="Write it in markdown…"
|
|
78
|
+
/>
|
|
79
|
+
</StoryCell>
|
|
80
|
+
|
|
81
|
+
<StoryCell align="stretch" label="inside a Field">
|
|
82
|
+
<Field
|
|
83
|
+
description="Markdown is what gets stored."
|
|
84
|
+
label="Acceptance criteria"
|
|
85
|
+
>
|
|
86
|
+
<MarkdownEditor defaultValue="- [ ] It **works**" />
|
|
87
|
+
</Field>
|
|
88
|
+
</StoryCell>
|
|
89
|
+
|
|
90
|
+
<StoryCell align="stretch" label="a whole document">
|
|
91
|
+
<MarkdownEditor
|
|
92
|
+
defaultValue={SAMPLE}
|
|
93
|
+
label="Long description"
|
|
94
|
+
/>
|
|
95
|
+
</StoryCell>
|
|
96
|
+
|
|
97
|
+
<StoryCell
|
|
98
|
+
align="stretch"
|
|
99
|
+
label="HTML is text, not markup"
|
|
100
|
+
>
|
|
101
|
+
<MarkdownEditor
|
|
102
|
+
defaultValue={
|
|
103
|
+
"<script>alert('xss')</script>\n\nA tag pasted in here is four coloured characters, because nothing in this component ever builds HTML.\n\n& < > survive as literal text too."
|
|
104
|
+
}
|
|
105
|
+
label="HTML description"
|
|
106
|
+
/>
|
|
107
|
+
</StoryCell>
|
|
108
|
+
</StoryGrid>
|
|
109
|
+
),
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export const AllStates: Story = {
|
|
113
|
+
args: { label: "Description" },
|
|
114
|
+
render: () => (
|
|
115
|
+
<StoryGrid columns={2}>
|
|
116
|
+
<StoryCell align="stretch" label="idle">
|
|
117
|
+
<MarkdownEditor
|
|
118
|
+
defaultValue="An **idle** editor."
|
|
119
|
+
label="Idle description"
|
|
120
|
+
/>
|
|
121
|
+
</StoryCell>
|
|
122
|
+
|
|
123
|
+
<StoryCell align="stretch" label="read only">
|
|
124
|
+
<MarkdownEditor
|
|
125
|
+
defaultValue="A **read-only** editor still highlights."
|
|
126
|
+
isReadOnly
|
|
127
|
+
label="Read-only description"
|
|
128
|
+
/>
|
|
129
|
+
</StoryCell>
|
|
130
|
+
|
|
131
|
+
<StoryCell align="stretch" label="disabled">
|
|
132
|
+
<MarkdownEditor
|
|
133
|
+
defaultValue="A **disabled** editor."
|
|
134
|
+
isDisabled
|
|
135
|
+
label="Disabled description"
|
|
136
|
+
/>
|
|
137
|
+
</StoryCell>
|
|
138
|
+
|
|
139
|
+
<StoryCell
|
|
140
|
+
align="stretch"
|
|
141
|
+
label="invalid, in a Field"
|
|
142
|
+
>
|
|
143
|
+
<Field
|
|
144
|
+
error="A description is required before a task can leave Backlog."
|
|
145
|
+
isRequired
|
|
146
|
+
label="Task description"
|
|
147
|
+
>
|
|
148
|
+
<MarkdownEditor defaultValue="" />
|
|
149
|
+
</Field>
|
|
150
|
+
</StoryCell>
|
|
151
|
+
</StoryGrid>
|
|
152
|
+
),
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The only honest way to story a container query: three fixed
|
|
157
|
+
* inline sizes, side by side, while the browser window never moves.
|
|
158
|
+
*
|
|
159
|
+
* The toolbar is this package's `Toolbar`, so it collapses into a
|
|
160
|
+
* **menu by measurement** rather than at a breakpoint — which is
|
|
161
|
+
* what the Narrow View actually needs, since a lane in a three-up
|
|
162
|
+
* board is narrow on a 4K display. The hint line under the surface
|
|
163
|
+
* is the container-query half: `sr-only` below `--cq-sm`, painted
|
|
164
|
+
* above it, and in the accessibility tree at every width.
|
|
165
|
+
*/
|
|
166
|
+
export const Responsive: Story = {
|
|
167
|
+
args: { label: "Description" },
|
|
168
|
+
render: () => (
|
|
169
|
+
<ContainerBoard>
|
|
170
|
+
{(width) => (
|
|
171
|
+
<MarkdownEditor
|
|
172
|
+
defaultValue={
|
|
173
|
+
"## Cut over\n\n- [ ] Label the leads\n- [ ] **Photograph** the cabling"
|
|
174
|
+
}
|
|
175
|
+
label={`Description at ${width}`}
|
|
176
|
+
/>
|
|
177
|
+
)}
|
|
178
|
+
</ContainerBoard>
|
|
179
|
+
),
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Type into it. The syntax colours as you go, and the markers on
|
|
184
|
+
* the line the caret is on paint in the accent colour while every
|
|
185
|
+
* other line's stay muted — that is the "raw syntax on the cursor's
|
|
186
|
+
* line" behaviour, in a medium where hiding the markers would move
|
|
187
|
+
* the text out from under the caret.
|
|
188
|
+
*
|
|
189
|
+
* Everything the toolbar does has a shortcut: **Ctrl+B**, **Ctrl+I**,
|
|
190
|
+
* **Ctrl+K**, **Ctrl+E**, **Ctrl+]** and **Ctrl+[**, and Enter
|
|
191
|
+
* continues a list. **Tab is never captured** — it moves focus, at
|
|
192
|
+
* every time, because a multi-line field on a form is exactly where
|
|
193
|
+
* somebody tabs onward.
|
|
194
|
+
*
|
|
195
|
+
* The upload here is a fake that resolves after a beat with a data
|
|
196
|
+
* URL, so the placeholder is visible while it runs. A real consumer
|
|
197
|
+
* returns a URL from its own blob storage.
|
|
198
|
+
*/
|
|
199
|
+
export const Interactive: Story = {
|
|
200
|
+
args: { label: "Description" },
|
|
201
|
+
render: function LiveEditor() {
|
|
202
|
+
const [stored, setStored] = useState(
|
|
203
|
+
"Paste an image, or press Ctrl+B and type.\n",
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
return (
|
|
207
|
+
<div className="flex flex-col gap-3">
|
|
208
|
+
<MarkdownEditor
|
|
209
|
+
label="Task description"
|
|
210
|
+
defaultValue={stored}
|
|
211
|
+
onChange={setStored}
|
|
212
|
+
onUploadImage={async (file) => {
|
|
213
|
+
await new Promise((resolve) => {
|
|
214
|
+
setTimeout(resolve, 600)
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
alt: file.name,
|
|
219
|
+
url: `https://example.invalid/blobs/${encodeURIComponent(file.name)}`,
|
|
220
|
+
}
|
|
221
|
+
}}
|
|
222
|
+
placeholder="Write it in markdown…"
|
|
223
|
+
/>
|
|
224
|
+
|
|
225
|
+
<div className="flex flex-col gap-1">
|
|
226
|
+
<span className="font-mono text-content-muted text-xs">
|
|
227
|
+
what gets stored
|
|
228
|
+
</span>
|
|
229
|
+
|
|
230
|
+
{/*
|
|
231
|
+
Wraps rather than scrolls. A scrollable region has to be
|
|
232
|
+
keyboard-reachable — axe's
|
|
233
|
+
`scrollable-region-focusable`, a real rule rather than a
|
|
234
|
+
nag — and `biome --write --unsafe` strips a `tabIndex`
|
|
235
|
+
off a non-interactive element, so the two fight. Not
|
|
236
|
+
being a scroll container settles it.
|
|
237
|
+
*/}
|
|
238
|
+
<pre className="whitespace-pre-wrap rounded-md bg-surface-sunken p-3 font-mono text-content-secondary text-sm wrap-anywhere">
|
|
239
|
+
{stored}
|
|
240
|
+
</pre>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
)
|
|
244
|
+
},
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Nothing but the surface, for a screenshot of the painted layer on
|
|
249
|
+
* its own.
|
|
250
|
+
*/
|
|
251
|
+
export const NoUpload: Story = {
|
|
252
|
+
args: {
|
|
253
|
+
defaultValue:
|
|
254
|
+
"# Heading\n\n**bold**, _italic_, `code`, ~~struck~~, [a link](https://example.invalid).\n\n- [ ] a task\n- [x] a done task\n\n> a quote\n",
|
|
255
|
+
label: "Description",
|
|
256
|
+
onUploadImage: undefined,
|
|
257
|
+
},
|
|
258
|
+
render: (args) => <MarkdownEditor {...args} />,
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export const Blank: Story = {
|
|
262
|
+
args: {
|
|
263
|
+
label: "Description",
|
|
264
|
+
onChange: noop,
|
|
265
|
+
placeholder: "Write it in markdown…",
|
|
266
|
+
},
|
|
267
|
+
}
|