@health-samurai/react-components 0.0.0-alpha.5 → 0.0.0-alpha.7

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 (146) hide show
  1. package/dist/bundle.css +318 -31
  2. package/dist/src/components/button-dropdown.d.ts +10 -0
  3. package/dist/src/components/button-dropdown.d.ts.map +1 -0
  4. package/dist/src/components/button-dropdown.js +70 -0
  5. package/dist/src/components/button-dropdown.js.map +1 -0
  6. package/dist/src/components/button-dropdown.stories.d.ts +11 -0
  7. package/dist/src/components/button-dropdown.stories.d.ts.map +1 -0
  8. package/dist/src/components/button-dropdown.stories.js +48 -0
  9. package/dist/src/components/button-dropdown.stories.js.map +1 -0
  10. package/dist/src/components/code-editor/index.d.ts +3 -2
  11. package/dist/src/components/code-editor/index.d.ts.map +1 -1
  12. package/dist/src/components/code-editor/index.js +152 -4
  13. package/dist/src/components/code-editor/index.js.map +1 -1
  14. package/dist/src/components/code-editor.stories.d.ts +1 -0
  15. package/dist/src/components/code-editor.stories.d.ts.map +1 -1
  16. package/dist/src/components/code-editor.stories.js +252 -1
  17. package/dist/src/components/code-editor.stories.js.map +1 -1
  18. package/dist/src/components/copy-icon.d.ts +5 -1
  19. package/dist/src/components/copy-icon.d.ts.map +1 -1
  20. package/dist/src/components/copy-icon.js +41 -3
  21. package/dist/src/components/copy-icon.js.map +1 -1
  22. package/dist/src/components/data-table.d.ts +9 -0
  23. package/dist/src/components/data-table.d.ts.map +1 -0
  24. package/dist/src/components/data-table.js +66 -0
  25. package/dist/src/components/data-table.js.map +1 -0
  26. package/dist/src/components/data-table.stories.d.ts +7 -0
  27. package/dist/src/components/data-table.stories.d.ts.map +1 -0
  28. package/dist/src/components/data-table.stories.js +240 -0
  29. package/dist/src/components/data-table.stories.js.map +1 -0
  30. package/dist/src/components/fhir-structure-view.d.ts +34 -0
  31. package/dist/src/components/fhir-structure-view.d.ts.map +1 -0
  32. package/dist/src/components/fhir-structure-view.js +226 -0
  33. package/dist/src/components/fhir-structure-view.js.map +1 -0
  34. package/dist/src/components/fhir-structure-view.stories.d.ts +7 -0
  35. package/dist/src/components/fhir-structure-view.stories.d.ts.map +1 -0
  36. package/dist/src/components/fhir-structure-view.stories.js +447 -0
  37. package/dist/src/components/fhir-structure-view.stories.js.map +1 -0
  38. package/dist/src/components/request-line-editor.d.ts +3 -1
  39. package/dist/src/components/request-line-editor.d.ts.map +1 -1
  40. package/dist/src/components/request-line-editor.js +26 -5
  41. package/dist/src/components/request-line-editor.js.map +1 -1
  42. package/dist/src/components/segment-control.d.ts +16 -0
  43. package/dist/src/components/segment-control.d.ts.map +1 -0
  44. package/dist/src/components/segment-control.js +48 -0
  45. package/dist/src/components/segment-control.js.map +1 -0
  46. package/dist/src/components/segment-control.stories.d.ts +15 -0
  47. package/dist/src/components/segment-control.stories.d.ts.map +1 -0
  48. package/dist/src/components/segment-control.stories.js +33 -0
  49. package/dist/src/components/segment-control.stories.js.map +1 -0
  50. package/dist/src/components/split-button.d.ts +5 -0
  51. package/dist/src/components/split-button.d.ts.map +1 -0
  52. package/dist/src/components/split-button.js +12 -0
  53. package/dist/src/components/split-button.js.map +1 -0
  54. package/dist/src/components/split-button.stories.d.ts +7 -0
  55. package/dist/src/components/split-button.stories.d.ts.map +1 -0
  56. package/dist/src/components/split-button.stories.js +57 -0
  57. package/dist/src/components/split-button.stories.js.map +1 -0
  58. package/dist/src/components/tree-view.d.ts +16 -7
  59. package/dist/src/components/tree-view.d.ts.map +1 -1
  60. package/dist/src/components/tree-view.js +75 -19
  61. package/dist/src/components/tree-view.js.map +1 -1
  62. package/dist/src/components/tree-view.stories.d.ts +3 -3
  63. package/dist/src/components/tree-view.stories.d.ts.map +1 -1
  64. package/dist/src/components/tree-view.stories.js +14 -5
  65. package/dist/src/components/tree-view.stories.js.map +1 -1
  66. package/dist/src/icons.d.ts +6 -0
  67. package/dist/src/icons.d.ts.map +1 -1
  68. package/dist/src/icons.js +235 -3
  69. package/dist/src/icons.js.map +1 -1
  70. package/dist/src/index.d.ts +10 -0
  71. package/dist/src/index.d.ts.map +1 -1
  72. package/dist/src/index.js +10 -0
  73. package/dist/src/index.js.map +1 -1
  74. package/dist/src/shadcn/components/ui/alert-dialog.d.ts +3 -1
  75. package/dist/src/shadcn/components/ui/alert-dialog.d.ts.map +1 -1
  76. package/dist/src/shadcn/components/ui/alert-dialog.js +5 -2
  77. package/dist/src/shadcn/components/ui/alert-dialog.js.map +1 -1
  78. package/dist/src/shadcn/components/ui/badge.d.ts +1 -1
  79. package/dist/src/shadcn/components/ui/card.d.ts +5 -1
  80. package/dist/src/shadcn/components/ui/card.d.ts.map +1 -1
  81. package/dist/src/shadcn/components/ui/card.js +21 -8
  82. package/dist/src/shadcn/components/ui/card.js.map +1 -1
  83. package/dist/src/shadcn/components/ui/card.stories.d.ts +302 -1
  84. package/dist/src/shadcn/components/ui/card.stories.d.ts.map +1 -1
  85. package/dist/src/shadcn/components/ui/card.stories.js +23 -2
  86. package/dist/src/shadcn/components/ui/card.stories.js.map +1 -1
  87. package/dist/src/shadcn/components/ui/combobox.d.ts +13 -0
  88. package/dist/src/shadcn/components/ui/combobox.d.ts.map +1 -1
  89. package/dist/src/shadcn/components/ui/combobox.js +102 -0
  90. package/dist/src/shadcn/components/ui/combobox.js.map +1 -1
  91. package/dist/src/shadcn/components/ui/dropdown-menu.d.ts.map +1 -1
  92. package/dist/src/shadcn/components/ui/dropdown-menu.js +1 -1
  93. package/dist/src/shadcn/components/ui/dropdown-menu.js.map +1 -1
  94. package/dist/src/shadcn/components/ui/input.d.ts +3 -1
  95. package/dist/src/shadcn/components/ui/input.d.ts.map +1 -1
  96. package/dist/src/shadcn/components/ui/input.js +39 -1
  97. package/dist/src/shadcn/components/ui/input.js.map +1 -1
  98. package/dist/src/shadcn/components/ui/pagination.d.ts +8 -1
  99. package/dist/src/shadcn/components/ui/pagination.d.ts.map +1 -1
  100. package/dist/src/shadcn/components/ui/pagination.js +36 -19
  101. package/dist/src/shadcn/components/ui/pagination.js.map +1 -1
  102. package/dist/src/shadcn/components/ui/pagination.stories.d.ts.map +1 -1
  103. package/dist/src/shadcn/components/ui/pagination.stories.js +44 -37
  104. package/dist/src/shadcn/components/ui/pagination.stories.js.map +1 -1
  105. package/dist/src/shadcn/components/ui/table.d.ts.map +1 -1
  106. package/dist/src/shadcn/components/ui/table.js +1 -1
  107. package/dist/src/shadcn/components/ui/table.js.map +1 -1
  108. package/dist/src/shadcn/components/ui/tabs.d.ts.map +1 -1
  109. package/dist/src/shadcn/components/ui/tabs.js +1 -0
  110. package/dist/src/shadcn/components/ui/tabs.js.map +1 -1
  111. package/dist/src/shadcn/components/ui/tree.d.ts +10 -2
  112. package/dist/src/shadcn/components/ui/tree.d.ts.map +1 -1
  113. package/dist/src/shadcn/components/ui/tree.js +31 -8
  114. package/dist/src/shadcn/components/ui/tree.js.map +1 -1
  115. package/dist/src/typography.css +36 -8
  116. package/package.json +5 -1
  117. package/src/components/button-dropdown.stories.tsx +41 -0
  118. package/src/components/button-dropdown.tsx +95 -0
  119. package/src/components/code-editor/index.tsx +129 -4
  120. package/src/components/code-editor.stories.tsx +294 -0
  121. package/src/components/copy-icon.tsx +57 -3
  122. package/src/components/data-table.stories.tsx +89 -0
  123. package/src/components/data-table.tsx +120 -0
  124. package/src/components/fhir-structure-view.stories.tsx +439 -0
  125. package/src/components/fhir-structure-view.tsx +229 -0
  126. package/src/components/request-line-editor.tsx +30 -4
  127. package/src/components/segment-control.stories.tsx +29 -0
  128. package/src/components/segment-control.tsx +81 -0
  129. package/src/components/split-button.stories.tsx +49 -0
  130. package/src/components/split-button.tsx +17 -0
  131. package/src/components/tree-view.stories.tsx +20 -15
  132. package/src/components/tree-view.tsx +118 -15
  133. package/src/icons.tsx +245 -3
  134. package/src/index.tsx +10 -2
  135. package/src/shadcn/components/ui/alert-dialog.tsx +6 -2
  136. package/src/shadcn/components/ui/card.stories.tsx +17 -3
  137. package/src/shadcn/components/ui/card.tsx +52 -8
  138. package/src/shadcn/components/ui/combobox.tsx +127 -0
  139. package/src/shadcn/components/ui/dropdown-menu.tsx +1 -2
  140. package/src/shadcn/components/ui/input.tsx +119 -0
  141. package/src/shadcn/components/ui/pagination.stories.tsx +8 -2
  142. package/src/shadcn/components/ui/pagination.tsx +54 -3
  143. package/src/shadcn/components/ui/table.tsx +6 -1
  144. package/src/shadcn/components/ui/tabs.tsx +1 -0
  145. package/src/shadcn/components/ui/tree.tsx +63 -10
  146. package/src/typography.css +36 -8
@@ -6,6 +6,8 @@ import {
6
6
  } from "@codemirror/autocomplete";
7
7
  import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
8
8
  import { json, jsonParseLinter } from "@codemirror/lang-json";
9
+ import { SQLDialect, sql } from "@codemirror/lang-sql";
10
+ import { yaml } from "@codemirror/lang-yaml";
9
11
  import {
10
12
  bracketMatching,
11
13
  foldGutter,
@@ -117,17 +119,128 @@ const customHighlightStyle = HighlightStyle.define([
117
119
  { tag: tags.number, color: "#00A984" },
118
120
  { tag: tags.bool, color: "#569cd6" },
119
121
  { tag: tags.null, color: "#569cd6" },
122
+ { tag: tags.keyword, color: "#569cd6" },
123
+ { tag: tags.operatorKeyword, color: "#405CBF" },
124
+ { tag: tags.controlKeyword, color: "#EA4A35" },
125
+ { tag: tags.typeName, color: "#00A984" },
126
+ { tag: tags.variableName, color: "#EA4A35" },
127
+ { tag: tags.operator, color: "#405CBF" },
128
+ { tag: tags.comment, color: "#00A984" },
129
+ { tag: tags.lineComment, color: "#00A984" },
130
+ { tag: tags.blockComment, color: "#00A984" },
120
131
  ]);
121
132
 
122
- type LanguageMode = "json" | "http";
133
+ const SQL_KEYWORDS = [
134
+ "select",
135
+ "from",
136
+ "where",
137
+ "and",
138
+ "or",
139
+ "not",
140
+ "in",
141
+ "between",
142
+ "like",
143
+ "insert",
144
+ "update",
145
+ "delete",
146
+ "create",
147
+ "drop",
148
+ "alter",
149
+ "table",
150
+ "index",
151
+ "join",
152
+ "inner",
153
+ "left",
154
+ "right",
155
+ "outer",
156
+ "on",
157
+ "as",
158
+ "order",
159
+ "by",
160
+ "group",
161
+ "having",
162
+ "limit",
163
+ "offset",
164
+ "union",
165
+ "intersect",
166
+ "except",
167
+ "distinct",
168
+ "all",
169
+ "exists",
170
+ "case",
171
+ "when",
172
+ "then",
173
+ "else",
174
+ "end",
175
+ "null",
176
+ "true",
177
+ "false",
178
+ "is",
179
+ "asc",
180
+ "desc",
181
+ ];
182
+
183
+ const SQL_BUILTIN = [
184
+ "varchar",
185
+ "char",
186
+ "text",
187
+ "integer",
188
+ "int",
189
+ "bigint",
190
+ "decimal",
191
+ "numeric",
192
+ "float",
193
+ "real",
194
+ "boolean",
195
+ "date",
196
+ "time",
197
+ "timestamp",
198
+ "uuid",
199
+ "count",
200
+ "sum",
201
+ "avg",
202
+ "min",
203
+ "max",
204
+ "coalesce",
205
+ "concat",
206
+ "substring",
207
+ "upper",
208
+ "lower",
209
+ "trim",
210
+ "length",
211
+ "now",
212
+ "current_date",
213
+ "current_time",
214
+ ];
215
+
216
+ const customSQLDialect = SQLDialect.define({
217
+ keywords: SQL_KEYWORDS.join(" "),
218
+ builtin: SQL_BUILTIN.join(" "),
219
+ });
220
+
221
+ type LanguageMode = "json" | "http" | "sql" | "yaml";
123
222
 
124
223
  function languageExtensions(mode: LanguageMode) {
125
224
  if (mode === "http") {
126
225
  const jsonLang = json();
226
+ const yamlLang = yaml();
227
+ return [
228
+ http((ct) =>
229
+ ct === "application/json"
230
+ ? jsonLang.language
231
+ : ct === "text/yaml"
232
+ ? yamlLang.language
233
+ : null,
234
+ ),
235
+ syntaxHighlighting(customHighlightStyle),
236
+ ];
237
+ } else if (mode === "sql") {
127
238
  return [
128
- http((ct) => (ct === "application/json" ? jsonLang.language : null)),
239
+ sql({ dialect: customSQLDialect }),
129
240
  syntaxHighlighting(customHighlightStyle),
130
241
  ];
242
+ } else if (mode === "yaml") {
243
+ return [yaml(), syntaxHighlighting(customHighlightStyle)];
131
244
  } else {
132
245
  return [
133
246
  json(),
@@ -139,6 +252,7 @@ function languageExtensions(mode: LanguageMode) {
139
252
 
140
253
  type CodeEditorProps = {
141
254
  readOnly?: boolean;
255
+ isReadOnlyTheme?: boolean;
142
256
  defaultValue?: string;
143
257
  currentValue?: string;
144
258
  onChange?: (value: string) => void;
@@ -159,6 +273,7 @@ export function CodeEditor({
159
273
  readOnly = false,
160
274
  id,
161
275
  mode = "json",
276
+ isReadOnlyTheme = false,
162
277
  }: CodeEditorProps) {
163
278
  const domRef = React.useRef(null);
164
279
  const [view, setView] = React.useState<EditorView | null>(null);
@@ -293,12 +408,22 @@ export function CodeEditor({
293
408
  readOnlyCompartment.current.reconfigure(
294
409
  EditorState.readOnly.of(readOnly),
295
410
  ),
411
+ ],
412
+ });
413
+ }, [readOnly, view]);
414
+
415
+ React.useEffect(() => {
416
+ if (view === null) {
417
+ return;
418
+ }
419
+ view.dispatch({
420
+ effects: [
296
421
  themeCompartment.current.reconfigure(
297
- readOnly ? readOnlyTheme : baseTheme,
422
+ isReadOnlyTheme ? readOnlyTheme : baseTheme,
298
423
  ),
299
424
  ],
300
425
  });
301
- }, [readOnly, view]);
426
+ }, [isReadOnlyTheme, view]);
302
427
 
303
428
  return <div className="h-full w-full" ref={domRef} id={id} />;
304
429
  }
@@ -1,4 +1,7 @@
1
+ import type { EditorView } from "@codemirror/view";
1
2
  import type { Meta, StoryObj } from "@storybook/react-vite";
3
+ import React from "react";
4
+ import { Input } from "#shadcn/components/ui/input.js";
2
5
  import { CodeEditor } from "./code-editor";
3
6
 
4
7
  const meta: Meta<typeof CodeEditor> = {
@@ -32,3 +35,294 @@ export const Default: Story = {
32
35
  </div>
33
36
  ),
34
37
  };
38
+
39
+ type ParsedHeader = {
40
+ name: string;
41
+ nameTrivia: string;
42
+ value: string;
43
+ valueTrivia: string;
44
+ };
45
+
46
+ type Parsed = {
47
+ method: string;
48
+ methodTrivia: string;
49
+ path: string;
50
+ pathTrivia: string;
51
+ headers: ParsedHeader[];
52
+ headersTrivia: string;
53
+ };
54
+
55
+ function parse(query: string): Parsed {
56
+ let hi = 0;
57
+ let lo = 0;
58
+ const res: Parsed = {
59
+ method: "",
60
+ methodTrivia: "",
61
+ path: "",
62
+ pathTrivia: "",
63
+ headers: [],
64
+ headersTrivia: "",
65
+ };
66
+
67
+ // Note that we iterate by code units, but it doesn't change correctness.
68
+ // method
69
+ for (hi = 0; hi < query.length; ++hi) {
70
+ const c = query[hi];
71
+ if (c === " " || c === "\t" || c === "\n") {
72
+ break;
73
+ }
74
+ }
75
+ res.method = query.substring(lo, hi);
76
+ lo = hi;
77
+ if (lo >= query.length) {
78
+ return res;
79
+ }
80
+
81
+ // method trivia
82
+ for (hi = lo; hi < query.length; ++hi) {
83
+ const c = query[hi];
84
+ if (!(c === " " || c === "\t")) {
85
+ break;
86
+ }
87
+ }
88
+ res.methodTrivia = query.substring(lo, hi);
89
+ lo = hi;
90
+ if (lo >= query.length) {
91
+ return res;
92
+ }
93
+
94
+ // path
95
+ for (hi = lo; hi < query.length; ++hi) {
96
+ const c = query[hi];
97
+ if (c === "\n") {
98
+ break;
99
+ }
100
+ }
101
+ res.path = query.substring(lo, hi);
102
+ lo = hi;
103
+ if (lo >= query.length) {
104
+ return res;
105
+ }
106
+
107
+ // path trivia
108
+ if (query[hi] === "\n") {
109
+ hi += 1;
110
+ res.pathTrivia = query.substring(lo, hi);
111
+ }
112
+ lo = hi;
113
+ if (lo >= query.length) {
114
+ return res;
115
+ }
116
+
117
+ // headers
118
+ let header: ParsedHeader = {
119
+ name: "",
120
+ nameTrivia: "",
121
+ value: "",
122
+ valueTrivia: "",
123
+ };
124
+ let headerReady = false;
125
+ // SAFETY: don't decrease hi inside this loop.
126
+ for (hi = lo; hi < query.length; ++hi) {
127
+ if (headerReady) {
128
+ res.headers.push(header);
129
+ }
130
+ header = { name: "", nameTrivia: "", value: "", valueTrivia: "" };
131
+ headerReady = false;
132
+
133
+ if (query[hi] === "\n") {
134
+ // end of headers
135
+ break;
136
+ }
137
+
138
+ // header name
139
+ for (lo = hi; hi <= query.length; ++hi) {
140
+ const c = query[hi];
141
+ if (c === " " || c === "\t" || c === "\n" || c === ":") {
142
+ break;
143
+ }
144
+ }
145
+ headerReady = true;
146
+ header.name = query.substring(lo, hi);
147
+ lo = hi;
148
+ if (lo >= query.length) {
149
+ break;
150
+ }
151
+
152
+ // header name trivia
153
+ let colonFound = false;
154
+ for (lo = hi; hi <= query.length; ++hi) {
155
+ const c = query[hi];
156
+ if (c === ":" && !colonFound) {
157
+ colonFound = true;
158
+ } else if (!(c === " " || c === "\t")) {
159
+ break;
160
+ }
161
+ }
162
+ header.nameTrivia = query.substring(lo, hi);
163
+ lo = hi;
164
+ if (lo >= query.length) {
165
+ break;
166
+ }
167
+
168
+ // header value
169
+ for (hi = lo; hi < query.length; ++hi) {
170
+ const c = query[hi];
171
+ if (c === "\n") {
172
+ break;
173
+ }
174
+ }
175
+ header.value = query.substring(lo, hi);
176
+ lo = hi;
177
+ if (lo >= query.length) {
178
+ break;
179
+ }
180
+
181
+ // header value trivia
182
+ if (query[hi] === "\n") {
183
+ header.valueTrivia = query.substring(lo, hi + 1);
184
+ }
185
+ lo = hi + 1;
186
+ if (lo >= query.length) {
187
+ break;
188
+ }
189
+ }
190
+ if (headerReady) {
191
+ res.headers.push(header);
192
+ }
193
+
194
+ if (query[hi] === "\n") {
195
+ res.headersTrivia = query.substring(lo, hi + 1);
196
+ }
197
+
198
+ return res;
199
+ }
200
+
201
+ const MethodInput = React.memo(function MethodInput({
202
+ method,
203
+ onMethodChange,
204
+ }: {
205
+ method: string;
206
+ onMethodChange: (ev: React.ChangeEvent<HTMLInputElement>) => void;
207
+ }) {
208
+ return (
209
+ <div className="flex justify-center items-baseline">
210
+ Method:
211
+ <Input
212
+ type="text"
213
+ className="inline"
214
+ value={method}
215
+ onChange={onMethodChange}
216
+ />
217
+ </div>
218
+ );
219
+ });
220
+
221
+ const PathInput = React.memo(function PathInput({
222
+ path,
223
+ onPathChange,
224
+ }: {
225
+ path: string;
226
+ onPathChange: (ev: React.ChangeEvent<HTMLInputElement>) => void;
227
+ }) {
228
+ return (
229
+ <div className="flex justify-center items-baseline">
230
+ {"Path: "}
231
+ <Input
232
+ type="text"
233
+ className="inline"
234
+ value={path}
235
+ onChange={onPathChange}
236
+ />
237
+ </div>
238
+ );
239
+ });
240
+
241
+ function ComplexComp() {
242
+ const [rawQuery, setRawQuery] = React.useState("");
243
+ const parsed = React.useMemo(() => parse(rawQuery), [rawQuery]);
244
+ const parsedRef = React.useRef(parsed);
245
+ React.useEffect(() => {
246
+ parsedRef.current = parsed;
247
+ }, [parsed]);
248
+ const method = React.useMemo(() => parsed.method, [parsed.method]);
249
+ const path = React.useMemo(() => parsed.path, [parsed.path]);
250
+
251
+ const viewRef = React.useRef<EditorView | null>(null);
252
+
253
+ const onMethodChange = React.useCallback(
254
+ (ev: React.ChangeEvent<HTMLInputElement>) => {
255
+ let newVal = ev.target.value;
256
+
257
+ if (newVal.indexOf(" ") !== -1) {
258
+ newVal = newVal.replaceAll(" ", "").replaceAll("\t", "");
259
+ }
260
+
261
+ const view = viewRef.current;
262
+ if (view === null) {
263
+ return null;
264
+ }
265
+
266
+ const from = 0;
267
+ const to = parsedRef.current.method.length;
268
+
269
+ view.dispatch({
270
+ changes: {
271
+ from: from,
272
+ to: to,
273
+ insert: newVal,
274
+ },
275
+ });
276
+ },
277
+ [],
278
+ );
279
+
280
+ const onPathChange = React.useCallback(
281
+ (ev: React.ChangeEvent<HTMLInputElement>) => {
282
+ const newVal = ev.target.value;
283
+
284
+ const view = viewRef.current;
285
+ if (view === null) {
286
+ return null;
287
+ }
288
+
289
+ const from =
290
+ parsedRef.current.method.length + parsedRef.current.methodTrivia.length;
291
+ const to = from + parsedRef.current.path.length;
292
+ console.log(from, to);
293
+
294
+ view.dispatch({
295
+ changes: {
296
+ from: from,
297
+ to: to,
298
+ insert: newVal,
299
+ },
300
+ });
301
+ },
302
+ [],
303
+ );
304
+
305
+ return (
306
+ <>
307
+ <MethodInput method={method} onMethodChange={onMethodChange} />
308
+ <PathInput path={path} onPathChange={onPathChange} />
309
+ <div className="h-[500px] w-[500px] border-black border-2">
310
+ <CodeEditor
311
+ mode="http"
312
+ onUpdate={(update) => {
313
+ if (update.docChanged) {
314
+ setRawQuery(update.state.doc.toString());
315
+ }
316
+ }}
317
+ viewCallback={(view) => {
318
+ viewRef.current = view;
319
+ }}
320
+ />
321
+ </div>
322
+ </>
323
+ );
324
+ }
325
+
326
+ export const Complex: Story = {
327
+ render: () => ComplexComp(),
328
+ };
@@ -1,17 +1,53 @@
1
1
  import { Check, Copy } from "lucide-react";
2
2
  import * as React from "react";
3
+ import { toast } from "sonner";
4
+ import {
5
+ Tooltip,
6
+ TooltipContent,
7
+ TooltipTrigger,
8
+ } from "#shadcn/components/ui/tooltip";
3
9
 
4
10
  interface CopyIconProps {
5
11
  text: string;
12
+ showTooltip?: boolean;
13
+ tooltipText?: string;
14
+ showToast?: boolean;
15
+ onCopy?: (text: string) => void;
6
16
  }
7
17
 
8
- function CopyIcon({ text }: CopyIconProps) {
18
+ function CopyIcon({
19
+ text,
20
+ showTooltip = true,
21
+ tooltipText = "Copy",
22
+ showToast = true,
23
+ onCopy,
24
+ ...props
25
+ }: CopyIconProps) {
9
26
  const [isActive, setIsActive] = React.useState(false);
10
27
 
11
28
  async function handleClick() {
12
29
  try {
13
30
  await navigator.clipboard.writeText(text);
14
31
  setIsActive(true);
32
+
33
+ if (showToast) {
34
+ const truncatedText =
35
+ text.length > 30 ? `${text.slice(0, 30)}...` : text;
36
+ toast(
37
+ <div className="flex flex-col gap-1">
38
+ <span className="typo-body">Successfully copied</span>
39
+ <span className="typo-code text-text-secondary">
40
+ {truncatedText}
41
+ </span>
42
+ </div>,
43
+ {
44
+ duration: 2000,
45
+ },
46
+ );
47
+ }
48
+
49
+ onCopy?.(text);
50
+
15
51
  setTimeout(() => {
16
52
  setIsActive(false);
17
53
  }, 1000);
@@ -20,11 +56,29 @@ function CopyIcon({ text }: CopyIconProps) {
20
56
  }
21
57
  }
22
58
 
23
- return (
24
- <button type="button" onClick={handleClick} style={{ cursor: "pointer" }}>
59
+ const button = (
60
+ <button
61
+ {...props}
62
+ type="button"
63
+ onClick={handleClick}
64
+ style={{ cursor: "pointer" }}
65
+ >
25
66
  {isActive ? <Check /> : <Copy />}
26
67
  </button>
27
68
  );
69
+
70
+ if (!showTooltip) {
71
+ return button;
72
+ }
73
+
74
+ return (
75
+ <Tooltip>
76
+ <TooltipTrigger asChild>{button}</TooltipTrigger>
77
+ <TooltipContent>
78
+ <p>{tooltipText}</p>
79
+ </TooltipContent>
80
+ </Tooltip>
81
+ );
28
82
  }
29
83
 
30
84
  export { CopyIcon };
@@ -0,0 +1,89 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { DataTable, type DataTableProps } from "./data-table";
3
+
4
+ const meta: Meta<typeof DataTable> = {
5
+ title: "Component/Data table",
6
+ component: DataTable,
7
+ tags: ["autodocs"],
8
+ };
9
+
10
+ export default meta;
11
+ type Story = StoryObj<typeof DataTable>;
12
+
13
+ function DataTableWrapper<TData, TValue>({
14
+ columns,
15
+ data,
16
+ }: DataTableProps<TData, TValue>) {
17
+ return <DataTable columns={columns} data={data} />;
18
+ }
19
+
20
+ export const Default: Story = {
21
+ args: {
22
+ columns: [
23
+ {
24
+ header: "Name",
25
+ accessorKey: "name",
26
+ },
27
+ {
28
+ header: "Age",
29
+ accessorKey: "age",
30
+ },
31
+ ],
32
+ data: [
33
+ { name: "John Doe", age: 30 },
34
+ { name: "Jane Smith", age: 25 },
35
+ { name: "Bob Johnson", age: 42 },
36
+ { name: "Alice Williams", age: 35 },
37
+ { name: "Charlie Brown", age: 28 },
38
+ { name: "Diana Prince", age: 31 },
39
+ { name: "Edward Norton", age: 45 },
40
+ { name: "Fiona Green", age: 27 },
41
+ { name: "George Miller", age: 38 },
42
+ { name: "Hannah Davis", age: 33 },
43
+ { name: "Ian Moore", age: 29 },
44
+ { name: "Julia Taylor", age: 41 },
45
+ { name: "Kevin Anderson", age: 36 },
46
+ { name: "Laura Thomas", age: 32 },
47
+ { name: "Michael Jackson", age: 44 },
48
+ { name: "Nancy Wilson", age: 26 },
49
+ { name: "Oscar Martinez", age: 39 },
50
+ { name: "Patricia Lee", age: 34 },
51
+ { name: "Quinn Harris", age: 37 },
52
+ { name: "Rachel Clark", age: 40 },
53
+ { name: "Samuel Wright", age: 43 },
54
+ { name: "Tina Turner", age: 48 },
55
+ { name: "Ulysses Grant", age: 52 },
56
+ { name: "Victoria Baker", age: 29 },
57
+ { name: "William Scott", age: 35 },
58
+ { name: "Xavier Adams", age: 31 },
59
+ { name: "Yolanda King", age: 38 },
60
+ { name: "Zachary Nelson", age: 27 },
61
+ { name: "Amy Carter", age: 33 },
62
+ { name: "Benjamin Hall", age: 46 },
63
+ { name: "Catherine Allen", age: 24 },
64
+ { name: "David Young", age: 41 },
65
+ { name: "Emily Walker", age: 36 },
66
+ { name: "Frank Robinson", age: 39 },
67
+ { name: "Grace White", age: 28 },
68
+ { name: "Henry Lewis", age: 47 },
69
+ { name: "Isabella Hill", age: 32 },
70
+ { name: "Jack Martin", age: 34 },
71
+ { name: "Katherine Garcia", age: 30 },
72
+ { name: "Louis Rodriguez", age: 45 },
73
+ { name: "Margaret Martinez", age: 37 },
74
+ { name: "Nathan Hernandez", age: 26 },
75
+ { name: "Olivia Lopez", age: 29 },
76
+ { name: "Peter Gonzalez", age: 43 },
77
+ { name: "Quincy Wilson", age: 38 },
78
+ { name: "Rebecca Anderson", age: 31 },
79
+ { name: "Steven Thomas", age: 44 },
80
+ { name: "Teresa Taylor", age: 35 },
81
+ { name: "Ursula Moore", age: 40 },
82
+ { name: "Victor Jackson", age: 42 },
83
+ ],
84
+ },
85
+ parameters: {
86
+ layout: "fullscreen",
87
+ },
88
+ render: (args) => <DataTableWrapper {...args} />,
89
+ };