@dreamtree-org/twreact-ui 1.3.1 → 1.3.3

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 (75) hide show
  1. package/DESIGN.md +2 -2
  2. package/README.md +90 -5
  3. package/ai-skills/dreamtree-ui.md +43 -4
  4. package/bin/cli.mjs +72 -4
  5. package/charts/package.json +5 -0
  6. package/dist/_shared/cn-DPPQUJu1.js +138 -0
  7. package/dist/ai-schema.json +639 -1
  8. package/dist/charts/index.d.ts +9 -0
  9. package/dist/charts/index.d.ts.map +1 -0
  10. package/dist/charts/index.js +797 -0
  11. package/dist/components/charts/AreaChart.d.ts +4 -0
  12. package/dist/components/charts/AreaChart.d.ts.map +1 -0
  13. package/dist/components/charts/BarChart.d.ts +4 -0
  14. package/dist/components/charts/BarChart.d.ts.map +1 -0
  15. package/dist/components/charts/CartesianChart.d.ts +5 -0
  16. package/dist/components/charts/CartesianChart.d.ts.map +1 -0
  17. package/dist/components/charts/ChartFrame.d.ts +18 -0
  18. package/dist/components/charts/ChartFrame.d.ts.map +1 -0
  19. package/dist/components/charts/DonutChart.d.ts +4 -0
  20. package/dist/components/charts/DonutChart.d.ts.map +1 -0
  21. package/dist/components/charts/LineChart.d.ts +4 -0
  22. package/dist/components/charts/LineChart.d.ts.map +1 -0
  23. package/dist/components/charts/Sparkline.d.ts +5 -0
  24. package/dist/components/charts/Sparkline.d.ts.map +1 -0
  25. package/dist/components/charts/chartTheme.d.ts +36 -0
  26. package/dist/components/charts/chartTheme.d.ts.map +1 -0
  27. package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
  28. package/dist/components/core/Table/MobileFilters.d.ts.map +1 -1
  29. package/dist/components/core/Table/Table.d.ts.map +1 -1
  30. package/dist/components/rich-text/RichTextEditor.d.ts +4 -0
  31. package/dist/components/rich-text/RichTextEditor.d.ts.map +1 -0
  32. package/dist/components/rich-text/RichTextToolbar.d.ts +219 -0
  33. package/dist/components/rich-text/RichTextToolbar.d.ts.map +1 -0
  34. package/dist/components/utility/Stepper.d.ts.map +1 -1
  35. package/dist/esm/charts/index.js +5 -0
  36. package/dist/esm/components/blocks/StatCard.js +1 -1
  37. package/dist/esm/components/charts/AreaChart.js +16 -0
  38. package/dist/esm/components/charts/BarChart.js +16 -0
  39. package/dist/esm/components/charts/CartesianChart.js +255 -0
  40. package/dist/esm/components/charts/ChartFrame.js +170 -0
  41. package/dist/esm/components/charts/DonutChart.js +122 -0
  42. package/dist/esm/components/charts/LineChart.js +16 -0
  43. package/dist/esm/components/charts/Sparkline.js +113 -0
  44. package/dist/esm/components/charts/chartTheme.js +126 -0
  45. package/dist/esm/components/core/Select.js +2 -2
  46. package/dist/esm/components/core/Table/MobileCard.js +5 -2
  47. package/dist/esm/components/core/Table/MobileFilters.js +10 -3
  48. package/dist/esm/components/core/Table/Table.js +10 -7
  49. package/dist/esm/components/rich-text/RichTextEditor.js +244 -0
  50. package/dist/esm/components/rich-text/RichTextToolbar.js +397 -0
  51. package/dist/esm/components/utility/Stepper.js +6 -4
  52. package/dist/esm/rich-text/index.js +1 -0
  53. package/dist/index.css +1 -1
  54. package/dist/index.esm.css +1 -1
  55. package/dist/index.esm.js +50 -22
  56. package/dist/index.js +50 -22
  57. package/dist/rich-text/index.d.ts +5 -0
  58. package/dist/rich-text/index.d.ts.map +1 -0
  59. package/dist/rich-text/index.js +654 -0
  60. package/dist/tokens/brands/practicepro.json +1 -0
  61. package/dist/tokens/brands/studio.css +14 -0
  62. package/dist/tokens/brands/studio.json +21 -0
  63. package/dist/types/charts.d.ts +97 -0
  64. package/dist/types/charts.d.ts.map +1 -0
  65. package/dist/types/rich-text.d.ts +50 -0
  66. package/dist/types/rich-text.d.ts.map +1 -0
  67. package/doc/README.md +13 -0
  68. package/mcp/catalog.snapshot.json +1016 -10
  69. package/mcp/server-core.mjs +30 -1
  70. package/package.json +39 -2
  71. package/rich-text/package.json +5 -0
  72. package/tokens/brand.schema.json +612 -0
  73. package/tokens/brands/practicepro.json +1 -0
  74. package/tokens/brands/studio.json +21 -0
  75. package/tokens/lib.cjs +131 -7
@@ -0,0 +1,397 @@
1
+ 'use client';
2
+ import { slicedToArray as _slicedToArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
4
+ import React, { useState, useRef, useEffect } from 'react';
5
+ import { Redo, Undo, Link, SquareCode, Quote, ListOrdered, List, Heading3, Heading2, Heading1, Code, Strikethrough, Italic, Bold } from 'lucide-react';
6
+ import { cn } from '../../utils/cn.js';
7
+
8
+ var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || "");
9
+ var shortcutLabel = function shortcutLabel(keys) {
10
+ return keys.replace("Mod", isMac ? "⌘" : "Ctrl").replace(/-/g, "+");
11
+ };
12
+ /** Every toolbar control, keyed by the name consumers pass in `toolbar`. */
13
+ var TOOLBAR_ITEMS = {
14
+ bold: {
15
+ label: "Bold",
16
+ icon: Bold,
17
+ group: "marks",
18
+ shortcut: "Mod-B",
19
+ toggle: true,
20
+ run: function run(c) {
21
+ return c.toggleBold();
22
+ }
23
+ },
24
+ italic: {
25
+ label: "Italic",
26
+ icon: Italic,
27
+ group: "marks",
28
+ shortcut: "Mod-I",
29
+ toggle: true,
30
+ run: function run(c) {
31
+ return c.toggleItalic();
32
+ }
33
+ },
34
+ strike: {
35
+ label: "Strikethrough",
36
+ icon: Strikethrough,
37
+ group: "marks",
38
+ shortcut: "Mod-Shift-S",
39
+ toggle: true,
40
+ run: function run(c) {
41
+ return c.toggleStrike();
42
+ }
43
+ },
44
+ code: {
45
+ label: "Inline code",
46
+ icon: Code,
47
+ group: "marks",
48
+ shortcut: "Mod-E",
49
+ toggle: true,
50
+ run: function run(c) {
51
+ return c.toggleCode();
52
+ }
53
+ },
54
+ heading1: {
55
+ label: "Heading 1",
56
+ icon: Heading1,
57
+ group: "blocks",
58
+ shortcut: "Mod-Alt-1",
59
+ toggle: true,
60
+ run: function run(c) {
61
+ return c.toggleHeading({
62
+ level: 1
63
+ });
64
+ }
65
+ },
66
+ heading2: {
67
+ label: "Heading 2",
68
+ icon: Heading2,
69
+ group: "blocks",
70
+ shortcut: "Mod-Alt-2",
71
+ toggle: true,
72
+ run: function run(c) {
73
+ return c.toggleHeading({
74
+ level: 2
75
+ });
76
+ }
77
+ },
78
+ heading3: {
79
+ label: "Heading 3",
80
+ icon: Heading3,
81
+ group: "blocks",
82
+ shortcut: "Mod-Alt-3",
83
+ toggle: true,
84
+ run: function run(c) {
85
+ return c.toggleHeading({
86
+ level: 3
87
+ });
88
+ }
89
+ },
90
+ bulletList: {
91
+ label: "Bulleted list",
92
+ icon: List,
93
+ group: "blocks",
94
+ shortcut: "Mod-Shift-8",
95
+ toggle: true,
96
+ run: function run(c) {
97
+ return c.toggleBulletList();
98
+ }
99
+ },
100
+ orderedList: {
101
+ label: "Numbered list",
102
+ icon: ListOrdered,
103
+ group: "blocks",
104
+ shortcut: "Mod-Shift-7",
105
+ toggle: true,
106
+ run: function run(c) {
107
+ return c.toggleOrderedList();
108
+ }
109
+ },
110
+ blockquote: {
111
+ label: "Quote",
112
+ icon: Quote,
113
+ group: "blocks",
114
+ shortcut: "Mod-Shift-B",
115
+ toggle: true,
116
+ run: function run(c) {
117
+ return c.toggleBlockquote();
118
+ }
119
+ },
120
+ codeBlock: {
121
+ label: "Code block",
122
+ icon: SquareCode,
123
+ group: "blocks",
124
+ shortcut: "Mod-Alt-C",
125
+ toggle: true,
126
+ run: function run(c) {
127
+ return c.toggleCodeBlock();
128
+ }
129
+ },
130
+ link: {
131
+ label: "Link",
132
+ icon: Link,
133
+ group: "insert",
134
+ toggle: true
135
+ },
136
+ undo: {
137
+ label: "Undo",
138
+ icon: Undo,
139
+ group: "history",
140
+ shortcut: "Mod-Z",
141
+ run: function run(c) {
142
+ return c.undo();
143
+ }
144
+ },
145
+ redo: {
146
+ label: "Redo",
147
+ icon: Redo,
148
+ group: "history",
149
+ shortcut: "Mod-Shift-Z",
150
+ run: function run(c) {
151
+ return c.redo();
152
+ }
153
+ }
154
+ };
155
+ var DEFAULT_TOOLBAR = ["bold", "italic", "strike", "code", "heading2", "heading3", "bulletList", "orderedList", "blockquote", "link", "undo", "redo"];
156
+ /** Toolbar state derived from the editor on every transaction (via useEditorState). */
157
+ function selectToolbarState(editor) {
158
+ if (!editor) return null;
159
+ return {
160
+ isEmpty: editor.isEmpty,
161
+ bold: editor.isActive("bold"),
162
+ italic: editor.isActive("italic"),
163
+ strike: editor.isActive("strike"),
164
+ code: editor.isActive("code"),
165
+ heading1: editor.isActive("heading", {
166
+ level: 1
167
+ }),
168
+ heading2: editor.isActive("heading", {
169
+ level: 2
170
+ }),
171
+ heading3: editor.isActive("heading", {
172
+ level: 3
173
+ }),
174
+ bulletList: editor.isActive("bulletList"),
175
+ orderedList: editor.isActive("orderedList"),
176
+ blockquote: editor.isActive("blockquote"),
177
+ codeBlock: editor.isActive("codeBlock"),
178
+ link: editor.isActive("link"),
179
+ undo: editor.can().undo(),
180
+ redo: editor.can().redo()
181
+ };
182
+ }
183
+ var SAFE_URL = /^(https?:|mailto:|tel:|\/|#)/i;
184
+ var HAS_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
185
+ /** Normalises a typed URL; returns null for schemes we refuse (javascript:, data:, …). */
186
+ function normalizeUrl(raw) {
187
+ var url = String(raw || "").trim();
188
+ if (!url) return "";
189
+ if (SAFE_URL.test(url)) return url;
190
+ if (HAS_SCHEME.test(url)) return null;
191
+ return "https://".concat(url);
192
+ }
193
+ function LinkForm(_ref) {
194
+ var editor = _ref.editor,
195
+ onClose = _ref.onClose;
196
+ var _useState = useState(function () {
197
+ return editor.getAttributes("link").href || "";
198
+ }),
199
+ _useState2 = _slicedToArray(_useState, 2),
200
+ href = _useState2[0],
201
+ setHref = _useState2[1];
202
+ var _useState3 = useState(false),
203
+ _useState4 = _slicedToArray(_useState3, 2),
204
+ invalid = _useState4[0],
205
+ setInvalid = _useState4[1];
206
+ var inputRef = useRef(null);
207
+ useEffect(function () {
208
+ var _inputRef$current;
209
+ (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 || _inputRef$current.focus();
210
+ }, []);
211
+ var close = function close() {
212
+ onClose();
213
+ editor.commands.focus();
214
+ };
215
+ var apply = function apply() {
216
+ var url = normalizeUrl(href);
217
+ if (url === null) {
218
+ setInvalid(true);
219
+ return;
220
+ }
221
+ var chain = editor.chain().focus().extendMarkRange("link");
222
+ if (!url) chain.unsetLink().run();else if (editor.state.selection.empty && !editor.isActive("link")) {
223
+ chain.insertContent({
224
+ type: "text",
225
+ text: url,
226
+ marks: [{
227
+ type: "link",
228
+ attrs: {
229
+ href: url
230
+ }
231
+ }]
232
+ }).run();
233
+ } else chain.setLink({
234
+ href: url
235
+ }).run();
236
+ onClose();
237
+ };
238
+ var remove = function remove() {
239
+ editor.chain().focus().extendMarkRange("link").unsetLink().run();
240
+ onClose();
241
+ };
242
+ return jsxs("div", {
243
+ className: "flex flex-wrap items-center gap-2 border-b border-gray-200 px-2 py-2 dark:border-gray-700",
244
+ children: [jsx("input", {
245
+ ref: inputRef,
246
+ type: "url",
247
+ value: href,
248
+ "aria-label": "Link URL",
249
+ "aria-invalid": invalid || undefined,
250
+ placeholder: "https://example.com",
251
+ onChange: function onChange(e) {
252
+ setHref(e.target.value);
253
+ setInvalid(false);
254
+ },
255
+ onKeyDown: function onKeyDown(e) {
256
+ if (e.key === "Enter") {
257
+ e.preventDefault();
258
+ apply();
259
+ } else if (e.key === "Escape") {
260
+ e.preventDefault();
261
+ close();
262
+ }
263
+ },
264
+ className: cn("h-8 min-w-0 flex-1 rounded-md border bg-white px-2 text-sm text-gray-900 placeholder-gray-400", "focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-gray-900 dark:text-gray-100 dark:placeholder-gray-500", invalid ? "border-error-500" : "border-gray-300 dark:border-gray-600")
265
+ }), jsx("button", {
266
+ type: "button",
267
+ onClick: apply,
268
+ className: formButton,
269
+ children: "Apply"
270
+ }), editor.isActive("link") && jsx("button", {
271
+ type: "button",
272
+ onClick: remove,
273
+ className: formButton,
274
+ children: "Remove link"
275
+ }), jsx("button", {
276
+ type: "button",
277
+ onClick: close,
278
+ className: formButton,
279
+ children: "Cancel"
280
+ }), invalid && jsx("p", {
281
+ className: "w-full text-xs text-error-600 dark:text-error-400",
282
+ role: "alert",
283
+ children: "Use an http(s), mailto: or tel: link."
284
+ })]
285
+ });
286
+ }
287
+ var formButton = "h-8 rounded-md px-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 dark:text-gray-200 dark:hover:bg-gray-800";
288
+ /**
289
+ * A WAI-ARIA toolbar: one tab stop, arrow keys / Home / End move between the
290
+ * buttons (roving tabindex), toggles report `aria-pressed`.
291
+ */
292
+ function RichTextToolbar(_ref2) {
293
+ var editor = _ref2.editor,
294
+ state = _ref2.state,
295
+ items = _ref2.items,
296
+ disabled = _ref2.disabled,
297
+ controlsId = _ref2.controlsId,
298
+ _ref2$label = _ref2.label,
299
+ label = _ref2$label === void 0 ? "Formatting" : _ref2$label;
300
+ var _useState5 = useState(0),
301
+ _useState6 = _slicedToArray(_useState5, 2),
302
+ focusIndex = _useState6[0],
303
+ setFocusIndex = _useState6[1];
304
+ var _useState7 = useState(false),
305
+ _useState8 = _slicedToArray(_useState7, 2),
306
+ linkOpen = _useState8[0],
307
+ setLinkOpen = _useState8[1];
308
+ var buttons = useRef([]);
309
+ var keys = items.filter(function (k) {
310
+ return TOOLBAR_ITEMS[k];
311
+ });
312
+ var moveFocus = function moveFocus(i) {
313
+ var _buttons$current$next;
314
+ var next = (i + keys.length) % keys.length;
315
+ setFocusIndex(next);
316
+ (_buttons$current$next = buttons.current[next]) === null || _buttons$current$next === void 0 || _buttons$current$next.focus();
317
+ };
318
+ var onKeyDown = function onKeyDown(e) {
319
+ var map = {
320
+ ArrowRight: focusIndex + 1,
321
+ ArrowLeft: focusIndex - 1,
322
+ Home: 0,
323
+ End: keys.length - 1
324
+ };
325
+ if (!(e.key in map)) return;
326
+ e.preventDefault();
327
+ moveFocus(map[e.key]);
328
+ };
329
+ var activate = function activate(key) {
330
+ if (!editor) return;
331
+ if (key === "link") {
332
+ setLinkOpen(function (open) {
333
+ return !open;
334
+ });
335
+ return;
336
+ }
337
+ var item = TOOLBAR_ITEMS[key];
338
+ if (!item.toggle && state && !state[key]) return;
339
+ item.run(editor.chain().focus()).run();
340
+ };
341
+ return jsxs(Fragment, {
342
+ children: [jsx("div", {
343
+ role: "toolbar",
344
+ "aria-label": label,
345
+ "aria-controls": controlsId,
346
+ "aria-orientation": "horizontal",
347
+ onKeyDown: onKeyDown,
348
+ className: "flex flex-wrap items-center gap-0.5 border-b border-gray-200 bg-gray-50 px-1 py-1 dark:border-gray-700 dark:bg-gray-800/60",
349
+ children: keys.map(function (key, i) {
350
+ var item = TOOLBAR_ITEMS[key];
351
+ var Icon = item.icon;
352
+ var pressed = item.toggle ? Boolean(state === null || state === void 0 ? void 0 : state[key]) || key === "link" && linkOpen : undefined;
353
+ var unavailable = !item.toggle && state ? !state[key] : false;
354
+ var newGroup = i > 0 && TOOLBAR_ITEMS[keys[i - 1]].group !== item.group;
355
+ return jsxs(React.Fragment, {
356
+ children: [newGroup && jsx("span", {
357
+ className: "mx-1 h-5 w-px bg-gray-300 dark:bg-gray-600",
358
+ "aria-hidden": "true"
359
+ }), jsx("button", {
360
+ ref: function ref(node) {
361
+ buttons.current[i] = node;
362
+ },
363
+ type: "button",
364
+ tabIndex: i === focusIndex ? 0 : -1,
365
+ "aria-label": item.label,
366
+ "aria-pressed": pressed,
367
+ "aria-disabled": unavailable || undefined,
368
+ "aria-keyshortcuts": item.shortcut ? item.shortcut.replace("Mod", isMac ? "Meta" : "Control").replace(/-/g, "+") : undefined,
369
+ title: item.shortcut ? "".concat(item.label, " (").concat(shortcutLabel(item.shortcut), ")") : item.label,
370
+ disabled: disabled || !editor,
371
+ onFocus: function onFocus() {
372
+ return setFocusIndex(i);
373
+ },
374
+ onMouseDown: function onMouseDown(e) {
375
+ return e.preventDefault();
376
+ },
377
+ onClick: function onClick() {
378
+ return activate(key);
379
+ },
380
+ className: cn("inline-flex h-8 w-8 items-center justify-center rounded-md text-gray-600 transition-colors", "hover:bg-gray-200 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-700 dark:hover:text-gray-100", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", "disabled:cursor-not-allowed disabled:opacity-50", pressed && "bg-primary-100 text-primary-700 dark:bg-primary-900/40 dark:text-primary-300", unavailable && "opacity-40"),
381
+ children: jsx(Icon, {
382
+ className: "h-4 w-4",
383
+ "aria-hidden": "true"
384
+ })
385
+ })]
386
+ }, key);
387
+ })
388
+ }), linkOpen && editor && jsx(LinkForm, {
389
+ editor: editor,
390
+ onClose: function onClose() {
391
+ return setLinkOpen(false);
392
+ }
393
+ })]
394
+ });
395
+ }
396
+
397
+ export { DEFAULT_TOOLBAR, RichTextToolbar, TOOLBAR_ITEMS, normalizeUrl, selectToolbarState };
@@ -34,9 +34,9 @@ var Stepper = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
34
34
  text: 'text-primary-600'
35
35
  },
36
36
  upcoming: {
37
- circle: 'bg-gray-300 text-primary-500',
37
+ circle: 'bg-gray-300 text-gray-700',
38
38
  line: 'bg-gray-300',
39
- text: 'text-primary-500'
39
+ text: 'text-muted'
40
40
  }
41
41
  };
42
42
  return jsx("nav", _objectSpread2(_objectSpread2({
@@ -70,8 +70,10 @@ var Stepper = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
70
70
  },
71
71
  disabled: !onStepClick || stepIndex > currentStep,
72
72
  "aria-current": status === 'current' ? 'step' : undefined,
73
+ "aria-label": "Step ".concat(stepIndex + 1).concat(step.title ? ": ".concat(step.title) : '').concat(status === 'completed' ? ' (completed)' : ''),
73
74
  children: status === 'completed' ? jsx(Check, {
74
- className: "h-4 w-4"
75
+ className: "h-4 w-4",
76
+ "aria-hidden": "true"
75
77
  }) : stepIndex + 1
76
78
  }), !isLast && jsx("div", {
77
79
  className: cn('bg-gray-300', {
@@ -88,7 +90,7 @@ var Stepper = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
88
90
  className: cn('text-sm font-medium', colors.text),
89
91
  children: step.title
90
92
  }), step.description && jsx("span", {
91
- className: "text-xs text-primary-500",
93
+ className: "text-xs text-muted",
92
94
  children: step.description
93
95
  })]
94
96
  })]
@@ -0,0 +1 @@
1
+ export { default as RichTextEditor } from '../components/rich-text/RichTextEditor.js';