@charcuterie/ui 3.0.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.
Files changed (113) hide show
  1. package/README.md +10 -0
  2. package/dist/Badge/Badge.d.ts +33 -3
  3. package/dist/Badge/Badge.d.ts.map +1 -1
  4. package/dist/Badge/Badge.js +20 -2
  5. package/dist/Badge/Badge.js.map +1 -1
  6. package/dist/Board/Board.d.ts +119 -0
  7. package/dist/Board/Board.d.ts.map +1 -0
  8. package/dist/Board/Board.js +165 -0
  9. package/dist/Board/Board.js.map +1 -0
  10. package/dist/Board/BoardCard.d.ts +120 -0
  11. package/dist/Board/BoardCard.d.ts.map +1 -0
  12. package/dist/Board/BoardCard.js +77 -0
  13. package/dist/Board/BoardCard.js.map +1 -0
  14. package/dist/Board/BoardLaneList.d.ts +103 -0
  15. package/dist/Board/BoardLaneList.d.ts.map +1 -0
  16. package/dist/Board/BoardLaneList.js +69 -0
  17. package/dist/Board/BoardLaneList.js.map +1 -0
  18. package/dist/Board/boardMove.d.ts +116 -0
  19. package/dist/Board/boardMove.d.ts.map +1 -0
  20. package/dist/Board/boardMove.js +116 -0
  21. package/dist/Board/boardMove.js.map +1 -0
  22. package/dist/Board/useBoardDrag.d.ts +44 -0
  23. package/dist/Board/useBoardDrag.d.ts.map +1 -0
  24. package/dist/Board/useBoardDrag.js +237 -0
  25. package/dist/Board/useBoardDrag.js.map +1 -0
  26. package/dist/Checkbox/Checkbox.d.ts.map +1 -1
  27. package/dist/Checkbox/Checkbox.js +15 -4
  28. package/dist/Checkbox/Checkbox.js.map +1 -1
  29. package/dist/DataTable/DataTable.d.ts +159 -0
  30. package/dist/DataTable/DataTable.d.ts.map +1 -0
  31. package/dist/DataTable/DataTable.js +197 -0
  32. package/dist/DataTable/DataTable.js.map +1 -0
  33. package/dist/DatePicker/DateGrid.d.ts +79 -0
  34. package/dist/DatePicker/DateGrid.d.ts.map +1 -0
  35. package/dist/DatePicker/DateGrid.js +220 -0
  36. package/dist/DatePicker/DateGrid.js.map +1 -0
  37. package/dist/DatePicker/DatePicker.d.ts +138 -0
  38. package/dist/DatePicker/DatePicker.d.ts.map +1 -0
  39. package/dist/DatePicker/DatePicker.js +384 -0
  40. package/dist/DatePicker/DatePicker.js.map +1 -0
  41. package/dist/DatePicker/datePresets.d.ts +29 -0
  42. package/dist/DatePicker/datePresets.d.ts.map +1 -0
  43. package/dist/DatePicker/datePresets.js +28 -0
  44. package/dist/DatePicker/datePresets.js.map +1 -0
  45. package/dist/DatePicker/parseDateInput.d.ts +106 -0
  46. package/dist/DatePicker/parseDateInput.d.ts.map +1 -0
  47. package/dist/DatePicker/parseDateInput.js +419 -0
  48. package/dist/DatePicker/parseDateInput.js.map +1 -0
  49. package/dist/DatePicker/plainDate.d.ts +167 -0
  50. package/dist/DatePicker/plainDate.d.ts.map +1 -0
  51. package/dist/DatePicker/plainDate.js +272 -0
  52. package/dist/DatePicker/plainDate.js.map +1 -0
  53. package/dist/MarkdownEditor/MarkdownEditor.d.ts +147 -0
  54. package/dist/MarkdownEditor/MarkdownEditor.d.ts.map +1 -0
  55. package/dist/MarkdownEditor/MarkdownEditor.js +492 -0
  56. package/dist/MarkdownEditor/MarkdownEditor.js.map +1 -0
  57. package/dist/MarkdownEditor/markdownCommands.d.ts +202 -0
  58. package/dist/MarkdownEditor/markdownCommands.d.ts.map +1 -0
  59. package/dist/MarkdownEditor/markdownCommands.js +379 -0
  60. package/dist/MarkdownEditor/markdownCommands.js.map +1 -0
  61. package/dist/MarkdownEditor/markdownSpans.d.ts +92 -0
  62. package/dist/MarkdownEditor/markdownSpans.d.ts.map +1 -0
  63. package/dist/MarkdownEditor/markdownSpans.js +303 -0
  64. package/dist/MarkdownEditor/markdownSpans.js.map +1 -0
  65. package/dist/categoricalStyles.d.ts +53 -0
  66. package/dist/categoricalStyles.d.ts.map +1 -0
  67. package/dist/categoricalStyles.js +195 -0
  68. package/dist/categoricalStyles.js.map +1 -0
  69. package/dist/index.d.ts +22 -0
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +11 -0
  72. package/dist/index.js.map +1 -1
  73. package/package.json +2 -2
  74. package/src/Badge/Badge.mdx +46 -0
  75. package/src/Badge/Badge.stories.tsx +98 -4
  76. package/src/Badge/Badge.test.tsx +157 -2
  77. package/src/Badge/Badge.tsx +49 -3
  78. package/src/Board/Board.mdx +199 -0
  79. package/src/Board/Board.stories.tsx +707 -0
  80. package/src/Board/Board.test.tsx +310 -0
  81. package/src/Board/Board.tsx +333 -0
  82. package/src/Board/BoardCard.tsx +290 -0
  83. package/src/Board/BoardLaneList.tsx +275 -0
  84. package/src/Board/boardMove.test.ts +213 -0
  85. package/src/Board/boardMove.ts +225 -0
  86. package/src/Board/useBoardDrag.ts +413 -0
  87. package/src/Checkbox/Checkbox.tsx +34 -3
  88. package/src/DataTable/DataTable.mdx +123 -0
  89. package/src/DataTable/DataTable.stories.tsx +411 -0
  90. package/src/DataTable/DataTable.test.tsx +386 -0
  91. package/src/DataTable/DataTable.tsx +497 -0
  92. package/src/DatePicker/DateGrid.tsx +467 -0
  93. package/src/DatePicker/DatePicker.mdx +170 -0
  94. package/src/DatePicker/DatePicker.stories.tsx +268 -0
  95. package/src/DatePicker/DatePicker.test.tsx +455 -0
  96. package/src/DatePicker/DatePicker.tsx +852 -0
  97. package/src/DatePicker/datePresets.ts +34 -0
  98. package/src/DatePicker/parseDateInput.test.ts +187 -0
  99. package/src/DatePicker/parseDateInput.ts +629 -0
  100. package/src/DatePicker/plainDate.test.ts +375 -0
  101. package/src/DatePicker/plainDate.ts +465 -0
  102. package/src/MarkdownEditor/MarkdownEditor.mdx +189 -0
  103. package/src/MarkdownEditor/MarkdownEditor.stories.tsx +267 -0
  104. package/src/MarkdownEditor/MarkdownEditor.test.tsx +627 -0
  105. package/src/MarkdownEditor/MarkdownEditor.tsx +862 -0
  106. package/src/MarkdownEditor/markdownCommands.test.ts +384 -0
  107. package/src/MarkdownEditor/markdownCommands.ts +566 -0
  108. package/src/MarkdownEditor/markdownSpans.test.ts +217 -0
  109. package/src/MarkdownEditor/markdownSpans.ts +458 -0
  110. package/src/argTypes.storyHelpers.ts +39 -0
  111. package/src/categoricalStyles.ts +244 -0
  112. package/src/index.ts +89 -0
  113. 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&amp; &lt; &gt; 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
+ }