@surrealdb/ui 1.2.16 → 1.2.18

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 (152) hide show
  1. package/dist/assets/1299e4695ad0bd61.svg +5 -0
  2. package/dist/assets/408117e904653548.svg +48 -0
  3. package/dist/assets/b516b020352f6369.svg +1 -0
  4. package/dist/assets/dfde8de566c3c2b9.svg +11 -0
  5. package/dist/assets/e9eae7bc863f211b.svg +1 -0
  6. package/dist/assets/f74ae3707a5d418f.svg +1 -0
  7. package/dist/icons.d.ts +6 -0
  8. package/dist/icons.js +198 -195
  9. package/dist/icons.js.map +1 -1
  10. package/dist/ui.d.ts +18 -0
  11. package/dist/ui.js +1441 -1426
  12. package/dist/ui.js.map +1 -1
  13. package/package.json +8 -2
  14. package/.claude/launch.json +0 -17
  15. package/.oxfmtrc.json +0 -27
  16. package/.oxlintrc.json +0 -23
  17. package/.picto-fix-png/Cursor.png +0 -0
  18. package/.picto-fix-png/DocumentGradient.png +0 -0
  19. package/.picto-fix-png/FileGradient.png +0 -0
  20. package/.picto-fix-png/HealthBubbleGradient.png +0 -0
  21. package/.picto-fix-png/LearnGradient.png +0 -0
  22. package/.picto-fix-png/MediaFileGradient.png +0 -0
  23. package/.zed/settings.json +0 -36
  24. package/AGENTS.md +0 -111
  25. package/CLAUDE.md +0 -111
  26. package/REVIEW.md +0 -81
  27. package/doc/code-style.md +0 -264
  28. package/doc/release.md +0 -102
  29. package/doc/stacker-plan.md +0 -219
  30. package/release-notes.md +0 -39
  31. package/tests/_setup/e2e-helpers.tsx +0 -169
  32. package/tests/_setup/markdown-classes.ts +0 -3
  33. package/tests/_setup/portable-stories.ts +0 -33
  34. package/tests/e2e/MarkdownEditor/__screenshots__/content-blocks.test.tsx/MarkdownEditor---content-blocks-continues-an-ordered-list-when-Enter-is-pressed-at-the-end-of-a-numbered-line-1.png +0 -0
  35. package/tests/e2e/MarkdownEditor/__screenshots__/content-blocks.test.tsx/MarkdownEditor---content-blocks-renders-a-diagram-for-the-fenced-mermaid-block-1.png +0 -0
  36. package/tests/e2e/MarkdownEditor/__screenshots__/content-blocks.test.tsx/MarkdownEditor---content-blocks-renders-a-horizontal-rule-as-a-separator-1.png +0 -0
  37. package/tests/e2e/MarkdownEditor/__screenshots__/content-blocks.test.tsx/MarkdownEditor---content-blocks-renders-a-read-only-table-preview-when-the-table-block-is-inactive-1.png +0 -0
  38. package/tests/e2e/MarkdownEditor/__screenshots__/content-blocks.test.tsx/MarkdownEditor---content-blocks-shows-blockquote-text-from-the-sample-document-1.png +0 -0
  39. package/tests/e2e/MarkdownEditor/__screenshots__/content-blocks.test.tsx/MarkdownEditor---content-blocks-shows-fenced-TypeScript-sample-code-in-the-document-1.png +0 -0
  40. package/tests/e2e/MarkdownEditor/__screenshots__/edits.test.tsx/MarkdownEditor---edits-auto-continues-a-bullet-list-when-Enter-is-pressed-at-the-end-of-a-list-item-1.png +0 -0
  41. package/tests/e2e/MarkdownEditor/__screenshots__/edits.test.tsx/MarkdownEditor---edits-expands-triple-backtick-into-a-fenced-code-block-with-the-caret-on-the-empty-body-line-1.png +0 -0
  42. package/tests/e2e/MarkdownEditor/__screenshots__/edits.test.tsx/MarkdownEditor---edits-reflects-typed-characters-in-the-underlying-document-1.png +0 -0
  43. package/tests/e2e/MarkdownEditor/__screenshots__/heading-fold.test.tsx/MarkdownEditor---heading-folds-viewer--folds-and-unfolds-a-heading-section-via-the-margin-control-1.png +0 -0
  44. package/tests/e2e/MarkdownEditor/__screenshots__/hybrid-widgets.test.tsx/MarkdownEditor---hybrid-widgets-clicking-a-callout-header-focuses-the-editor-and-parks-the-caret-inside-the-callout--REASONING--4--1.png +0 -0
  45. package/tests/e2e/MarkdownEditor/__screenshots__/hybrid-widgets.test.tsx/MarkdownEditor---hybrid-widgets-keeps-list-bullets-consistent-after-hopping-the-caret-across-items-several-times-1.png +0 -0
  46. package/tests/e2e/MarkdownEditor/__screenshots__/hybrid-widgets.test.tsx/MarkdownEditor---hybrid-widgets-reveals-heading-marks-when-the-caret-enters-the-heading-line-and-hides-them-when-it-leaves-1.png +0 -0
  47. package/tests/e2e/MarkdownEditor/__screenshots__/hybrid-widgets.test.tsx/MarkdownEditor---hybrid-widgets-shows-the-right-callout-title-when-moving-focus-between-consecutive-callouts-1.png +0 -0
  48. package/tests/e2e/MarkdownEditor/__screenshots__/hybrid-widgets.test.tsx/MarkdownEditor---preview-widgets-clicking-a-callout-header-focuses-the-editor-with-the-caret-in-that-callout-1.png +0 -0
  49. package/tests/e2e/MarkdownEditor/__screenshots__/hybrid-widgets.test.tsx/MarkdownEditor---preview-widgets-keeps-list-bullets-consistent-after-hopping-the-caret-across-items-several-times-1.png +0 -0
  50. package/tests/e2e/MarkdownEditor/__screenshots__/hybrid-widgets.test.tsx/MarkdownEditor---preview-widgets-shows-the-right-callout-title-when-moving-focus-between-consecutive-callouts-1.png +0 -0
  51. package/tests/e2e/MarkdownEditor/__screenshots__/jsx-block-content.test.tsx/MarkdownEditor---block-JSX-components-clicking-the-edit-source-action-selects-the-component-source-range-1.png +0 -0
  52. package/tests/e2e/MarkdownEditor/__screenshots__/jsx-block-content.test.tsx/MarkdownEditor---block-JSX-components-renders-block-components-via-JsxBlockWidget-with-an-edit-source-action-1.png +0 -0
  53. package/tests/e2e/MarkdownEditor/__screenshots__/jsx-block-content.test.tsx/MarkdownEditor---inline-JSX-rendering-block-content-keeps-multiple-inline-JSX-widgets-on-the-same-line-side-by-side-1.png +0 -0
  54. package/tests/e2e/MarkdownEditor/__screenshots__/jsx-highlight.test.tsx/MarkdownEditor---JSX-attribute-highlighting-does-not-let-the-nested-HTML-parser-mis-highlight-attributes-after-an-expression-1.png +0 -0
  55. package/tests/e2e/MarkdownEditor/__screenshots__/jsx-inline-click.test.tsx/MarkdownEditor---inline-JSX-click-reveal-reveals-the-raw-source-when-an-inline-component-badge-is-clicked-1.png +0 -0
  56. package/tests/e2e/MarkdownEditor/__screenshots__/jsx-inline-click.test.tsx/MarkdownEditor---inline-JSX-click-reveal-reveals-the-raw-source-when-an-inline-component-badge-is-clicked-2.png +0 -0
  57. package/tests/e2e/MarkdownEditor/__screenshots__/jsx-inline-click.test.tsx/MarkdownEditor---inline-JSX-click-reveal-reveals-the-raw-source-when-an-inline-component-badge-is-clicked-3.png +0 -0
  58. package/tests/e2e/MarkdownEditor/__screenshots__/jsx-selection.test.tsx/MarkdownEditor---JSX-selection-reveal-shows-JSX-widget-when-inactive-and-raw-source-when-caret-is-inside-the-tag-1.png +0 -0
  59. package/tests/e2e/MarkdownEditor/__screenshots__/media-sizing.test.tsx/MarkdownEditor---media-sizing-images-and-videos-do-not-exceed-the-editor-content-width-1.png +0 -0
  60. package/tests/e2e/MarkdownEditor/__screenshots__/media-sizing.test.tsx/MarkdownEditor---media-sizing-matches-MarkdownViewer-image-width-in-the-split-playground-1.png +0 -0
  61. package/tests/e2e/MarkdownEditor/__screenshots__/modes.test.tsx/MarkdownEditor---modes-standalone-MarkdownViewer-is-not-a-CodeMirror-surface-1.png +0 -0
  62. package/tests/e2e/MarkdownEditor/__screenshots__/modes.test.tsx/MarkdownEditor---modes-toggling-the-SegmentedControl-swaps-mode-without-remounting-the-editor-1.png +0 -0
  63. package/tests/e2e/MarkdownEditor/__screenshots__/regressions.test.tsx/MarkdownEditor---regressions-repeated-checkbox-toggles-do-not-duplicate-or-drift-task-markers-1.png +0 -0
  64. package/tests/e2e/MarkdownEditor/__screenshots__/regressions.test.tsx/MarkdownEditor---regressions-scroll-position-is-preserved-when-the-document-is-edited--chat-92584463--1.png +0 -0
  65. package/tests/e2e/MarkdownEditor/__screenshots__/regressions.test.tsx/MarkdownEditor---regressions-task-checkbox-toggles-between-checked-and-unchecked-in-the-source-document-1.png +0 -0
  66. package/tests/e2e/MarkdownEditor/__screenshots__/regressions.test.tsx/MarkdownEditor---regressions-toggle-via-checkbox-preserves-task-marker-widgets-visible-from-the-previous-caret-position-1.png +0 -0
  67. package/tests/e2e/MarkdownEditor/__screenshots__/slash-commands.test.tsx/MarkdownEditor---slash-commands-dismisses-on-Escape-and-leaves-the-slash-as-literal-text-1.png +0 -0
  68. package/tests/e2e/MarkdownEditor/__screenshots__/slash-commands.test.tsx/MarkdownEditor---slash-commands-highlights-the-slash-and-shows-an-Enter-command-placeholder-until-text-is-typed-1.png +0 -0
  69. package/tests/e2e/MarkdownEditor/__screenshots__/slash-commands.test.tsx/MarkdownEditor---slash-commands-opens-a-filtered--keyboard-navigable-menu-and-inserts-boilerplate-on-Enter-1.png +0 -0
  70. package/tests/e2e/MarkdownEditor/__screenshots__/undo-redo.test.tsx/MarkdownEditor---undo-and-redo-restores-undone-document-edits-via-redo-1.png +0 -0
  71. package/tests/e2e/MarkdownEditor/content-blocks.test.tsx +0 -153
  72. package/tests/e2e/MarkdownEditor/edits.test.tsx +0 -112
  73. package/tests/e2e/MarkdownEditor/heading-fold.test.tsx +0 -45
  74. package/tests/e2e/MarkdownEditor/hybrid-widgets.test.tsx +0 -193
  75. package/tests/e2e/MarkdownEditor/image-on-image.test.tsx +0 -73
  76. package/tests/e2e/MarkdownEditor/jsx-block-content.test.tsx +0 -243
  77. package/tests/e2e/MarkdownEditor/jsx-highlight.test.tsx +0 -69
  78. package/tests/e2e/MarkdownEditor/jsx-inline-badges.test.tsx +0 -60
  79. package/tests/e2e/MarkdownEditor/jsx-inline-click.test.tsx +0 -54
  80. package/tests/e2e/MarkdownEditor/jsx-selection.test.tsx +0 -44
  81. package/tests/e2e/MarkdownEditor/link-placeholder.test.tsx +0 -68
  82. package/tests/e2e/MarkdownEditor/media-align.test.tsx +0 -58
  83. package/tests/e2e/MarkdownEditor/media-edit.test.tsx +0 -64
  84. package/tests/e2e/MarkdownEditor/media-sizing.test.tsx +0 -124
  85. package/tests/e2e/MarkdownEditor/modes.test.tsx +0 -94
  86. package/tests/e2e/MarkdownEditor/onimage-parity.test.tsx +0 -50
  87. package/tests/e2e/MarkdownEditor/regressions.test.tsx +0 -223
  88. package/tests/e2e/MarkdownEditor/slash-commands.test.tsx +0 -100
  89. package/tests/e2e/MarkdownEditor/table-click.test.tsx +0 -48
  90. package/tests/e2e/MarkdownEditor/table-controls.test.tsx +0 -57
  91. package/tests/e2e/MarkdownEditor/table-format.test.tsx +0 -42
  92. package/tests/e2e/MarkdownEditor/undo-redo.test.tsx +0 -39
  93. package/tests/e2e/MarkdownViewer/__screenshots__/parity.test.tsx/MarkdownViewer---editor-parity-matches-computed-font-size-on-first-heading-1.png +0 -0
  94. package/tests/e2e/MarkdownViewer/__screenshots__/parity.test.tsx/MarkdownViewer---editor-parity-matches-counts-for-shared-structural-classes-1.png +0 -0
  95. package/tests/e2e/MarkdownViewer/__screenshots__/parity.test.tsx/MarkdownViewer---editor-parity-matches-visible-text-between-preview-editor--blurred--and-MarkdownViewer-1.png +0 -0
  96. package/tests/e2e/MarkdownViewer/__screenshots__/render.test.tsx/MarkdownViewer---render-exercises-shared-preview-class-names-without-mounting-CodeMirror-1.png +0 -0
  97. package/tests/e2e/MarkdownViewer/parity.test.tsx +0 -191
  98. package/tests/e2e/MarkdownViewer/render.test.tsx +0 -36
  99. package/tests/e2e/Stacker/stacker.test.tsx +0 -304
  100. package/tests/unit/Editor/helpers.test.ts +0 -42
  101. package/tests/unit/MarkdownConformance/error-isolation.test.tsx +0 -44
  102. package/tests/unit/MarkdownConformance/indentation.test.tsx +0 -30
  103. package/tests/unit/MarkdownConformance/inline-code-fuzz.test.tsx +0 -255
  104. package/tests/unit/MarkdownConformance/jsx-attributes.test.tsx +0 -57
  105. package/tests/unit/MarkdownConformance/jsx-fuzz.test.tsx +0 -165
  106. package/tests/unit/MarkdownConformance/links.test.tsx +0 -95
  107. package/tests/unit/MarkdownConformance/render-helpers.tsx +0 -88
  108. package/tests/unit/MarkdownEditor/code-info.test.ts +0 -63
  109. package/tests/unit/MarkdownEditor/decorations.test.ts +0 -490
  110. package/tests/unit/MarkdownEditor/editor-ready.test.ts +0 -36
  111. package/tests/unit/MarkdownEditor/html-descriptors.test.ts +0 -94
  112. package/tests/unit/MarkdownEditor/indented-fence.test.ts +0 -103
  113. package/tests/unit/MarkdownEditor/jsx-attr-scan.test.ts +0 -115
  114. package/tests/unit/MarkdownEditor/jsx-block-widget.test.ts +0 -92
  115. package/tests/unit/MarkdownEditor/jsx-tag-grammar.test.ts +0 -88
  116. package/tests/unit/MarkdownEditor/list-indent.test.ts +0 -95
  117. package/tests/unit/MarkdownEditor/slash-commands.test.ts +0 -213
  118. package/tests/unit/MarkdownEditor/table-format.test.ts +0 -83
  119. package/tests/unit/MarkdownEditor/table.test.ts +0 -119
  120. package/tests/unit/MarkdownEditor/triggers.test.ts +0 -244
  121. package/tests/unit/MarkdownEditor/widget-store.test.ts +0 -105
  122. package/tests/unit/MarkdownViewer/callout.test.tsx +0 -60
  123. package/tests/unit/MarkdownViewer/code-highlight.test.tsx +0 -61
  124. package/tests/unit/MarkdownViewer/code-title.test.tsx +0 -62
  125. package/tests/unit/MarkdownViewer/features.test.tsx +0 -164
  126. package/tests/unit/MarkdownViewer/headings.test.tsx +0 -40
  127. package/tests/unit/MarkdownViewer/indented-jsx-children.test.tsx +0 -98
  128. package/tests/unit/MarkdownViewer/jsx-block-nesting.test.tsx +0 -234
  129. package/tests/unit/MarkdownViewer/jsx.test.tsx +0 -211
  130. package/tests/unit/MarkdownViewer/list-bullets.test.tsx +0 -49
  131. package/tests/unit/MarkdownViewer/list-code.test.tsx +0 -65
  132. package/tests/unit/MarkdownViewer/preserve-newlines.test.tsx +0 -143
  133. package/tests/unit/MarkdownViewer/read-time.test.ts +0 -21
  134. package/tests/unit/MarkdownViewer/renderers.test.tsx +0 -95
  135. package/tests/unit/MarkdownViewer/runnable.test.tsx +0 -69
  136. package/tests/unit/MarkdownViewer/ssr.test.tsx +0 -94
  137. package/tests/unit/MarkdownViewer/syntax-highlighting.test.tsx +0 -74
  138. package/tests/unit/MarkdownViewer/tabs-fenced-code.test.tsx +0 -196
  139. package/tests/unit/MarkdownViewer/tabs.test.tsx +0 -116
  140. package/tests/unit/Stacker/drag.test.ts +0 -21
  141. package/tests/unit/Stacker/helpers.test.ts +0 -105
  142. package/tests/unit/Stacker/reducer.test.ts +0 -107
  143. package/tests/unit/Syntax/language.test.ts +0 -63
  144. package/tools/duplicate-vector-mappings.json +0 -143
  145. package/tools/glass-export-overrides.json +0 -8
  146. package/tools/icon-parser.ts +0 -78
  147. package/tools/integration-gradient-exports.json +0 -57
  148. package/tools/picto-compare.ts +0 -64
  149. package/tools/picto-merge-urls.ts +0 -43
  150. package/tools/picto-sync.ts +0 -630
  151. package/tools/picto-verify-gradients.ts +0 -86
  152. package/tools/vector-export-nodes.json +0 -977
@@ -1,105 +0,0 @@
1
- import {
2
- coveredEphemeral,
3
- drawerDepthStyle,
4
- resolveKind,
5
- resolveLiveKind,
6
- topOpened,
7
- } from "@src/lib/stacker";
8
- import type { StackerItem } from "@src/lib/stacker";
9
- import { describe, expect, it } from "vitest";
10
-
11
- describe("resolveKind", () => {
12
- it("uses the explicit variant when provided", () => {
13
- expect(resolveKind("drawer", false)).toBe("drawer");
14
- expect(resolveKind("modal", true)).toBe("modal");
15
- });
16
-
17
- it("falls back to the viewport when no variant is set", () => {
18
- expect(resolveKind(undefined, true)).toBe("drawer");
19
- expect(resolveKind(undefined, false)).toBe("modal");
20
- });
21
- });
22
-
23
- describe("resolveLiveKind", () => {
24
- const drawerFirst: StackerItem[] = [
25
- { id: "a", opened: true, settings: { variant: "drawer" } },
26
- { id: "b", opened: true, settings: { variant: "modal" } },
27
- ];
28
-
29
- it("returns null for an empty stack", () => {
30
- expect(resolveLiveKind([], false)).toBeNull();
31
- });
32
-
33
- it("follows the first item's variant hint on desktop", () => {
34
- expect(resolveLiveKind(drawerFirst, false)).toBe("drawer");
35
- });
36
-
37
- it("follows the viewport when the first item has no variant", () => {
38
- const items: StackerItem[] = [{ id: "a", opened: true, settings: {} }];
39
- expect(resolveLiveKind(items, true)).toBe("drawer");
40
- expect(resolveLiveKind(items, false)).toBe("modal");
41
- });
42
-
43
- it("prefers a stack-level forced kind over the first item and viewport", () => {
44
- const items: StackerItem[] = [{ id: "b", opened: true, settings: { variant: "modal" } }];
45
- expect(resolveLiveKind(items, false, "drawer")).toBe("drawer");
46
- expect(resolveLiveKind(items, true, "modal")).toBe("modal");
47
- });
48
- });
49
-
50
- describe("topOpened", () => {
51
- const items: StackerItem[] = [
52
- { id: "a", opened: true, settings: {} },
53
- { id: "b", opened: true, settings: {} },
54
- { id: "c", opened: false, settings: {} },
55
- ];
56
-
57
- it("returns the top-most open item, skipping closing ones", () => {
58
- expect(topOpened(items)?.id).toBe("b");
59
- expect(topOpened([])).toBeUndefined();
60
- });
61
- });
62
-
63
- describe("coveredEphemeral", () => {
64
- it("returns open ephemeral items that would be covered by a new top", () => {
65
- const items: StackerItem[] = [
66
- { id: "a", opened: true, settings: { ephemeral: true } },
67
- { id: "b", opened: true, settings: {} },
68
- { id: "c", opened: false, settings: { ephemeral: true } },
69
- ];
70
- expect(coveredEphemeral(items, "new").map((i) => i.id)).toEqual(["a"]);
71
- });
72
-
73
- it("excludes the new top id even if that item is ephemeral", () => {
74
- const items: StackerItem[] = [{ id: "a", opened: true, settings: { ephemeral: true } }];
75
- expect(coveredEphemeral(items, "a")).toEqual([]);
76
- });
77
- });
78
-
79
- describe("drawerDepthStyle", () => {
80
- it("applies no transform at depth 0", () => {
81
- expect(drawerDepthStyle("right", 0)).toEqual({
82
- transform: "none",
83
- transformOrigin: "center",
84
- });
85
- });
86
-
87
- it("pushes outward from the free edge and scales down per side", () => {
88
- expect(drawerDepthStyle("right", 1)).toEqual({
89
- transform: "translateX(-12px) scale(0.96)",
90
- transformOrigin: "0% 50%",
91
- });
92
- expect(drawerDepthStyle("left", 1)).toEqual({
93
- transform: "translateX(12px) scale(0.96)",
94
- transformOrigin: "100% 50%",
95
- });
96
- expect(drawerDepthStyle("bottom", 2)).toEqual({
97
- transform: "translateY(-24px) scale(0.92)",
98
- transformOrigin: "50% 0%",
99
- });
100
- expect(drawerDepthStyle("top", 2)).toEqual({
101
- transform: "translateY(24px) scale(0.92)",
102
- transformOrigin: "50% 100%",
103
- });
104
- });
105
- });
@@ -1,107 +0,0 @@
1
- import { STACKER_INITIAL_STATE, type StackerState, stackerReducer } from "@src/lib/stacker";
2
- import type { StackerItem } from "@src/lib/stacker";
3
- import { describe, expect, it } from "vitest";
4
-
5
- function item(id: string): StackerItem {
6
- return { id, opened: true, settings: { title: id } };
7
- }
8
-
9
- function open(state: StackerState, id: string): StackerState {
10
- return stackerReducer(state, { type: "OPEN", item: item(id) });
11
- }
12
-
13
- describe("stackerReducer", () => {
14
- it("appends overlays in order", () => {
15
- let state = open(STACKER_INITIAL_STATE, "a");
16
- state = open(state, "b");
17
- expect(state.items.map((i) => i.id)).toEqual(["a", "b"]);
18
- });
19
-
20
- it("no-ops when reopening an already-open id", () => {
21
- const state = open(STACKER_INITIAL_STATE, "a");
22
- expect(open(state, "a")).toBe(state);
23
- });
24
-
25
- it("revives a closing overlay in place and merges settings", () => {
26
- let state = open(STACKER_INITIAL_STATE, "a");
27
- state = stackerReducer(state, { type: "CLOSE", id: "a" });
28
- expect(state.items[0].opened).toBe(false);
29
-
30
- state = stackerReducer(state, {
31
- type: "OPEN",
32
- item: { id: "a", opened: true, settings: { title: "revived" } },
33
- });
34
- expect(state.items).toHaveLength(1);
35
- expect(state.items[0].opened).toBe(true);
36
- expect(state.items[0].settings.title).toBe("revived");
37
- });
38
-
39
- it("flips opened on CLOSE and is idempotent", () => {
40
- const state = open(STACKER_INITIAL_STATE, "a");
41
- const closed = stackerReducer(state, { type: "CLOSE", id: "a" });
42
- expect(closed.items[0].opened).toBe(false);
43
- expect(stackerReducer(closed, { type: "CLOSE", id: "a" })).toBe(closed);
44
- expect(stackerReducer(state, { type: "CLOSE", id: "missing" })).toBe(state);
45
- });
46
-
47
- it("removes an item only on REMOVE", () => {
48
- let state = open(STACKER_INITIAL_STATE, "a");
49
- state = open(state, "b");
50
-
51
- state = stackerReducer(state, { type: "REMOVE", id: "b" });
52
- expect(state.items.map((i) => i.id)).toEqual(["a"]);
53
-
54
- state = stackerReducer(state, { type: "REMOVE", id: "a" });
55
- expect(state.items).toHaveLength(0);
56
- });
57
-
58
- it("locks a founding forced variant until the stack empties", () => {
59
- let state = stackerReducer(STACKER_INITIAL_STATE, {
60
- type: "OPEN",
61
- item: {
62
- id: "ephemeral",
63
- opened: true,
64
- settings: { variant: "drawer", ephemeral: true },
65
- },
66
- });
67
- expect(state.forcedKind).toBe("drawer");
68
-
69
- state = stackerReducer(state, {
70
- type: "OPEN",
71
- item: { id: "next", opened: true, settings: { variant: "modal" } },
72
- });
73
- expect(state.forcedKind).toBe("drawer");
74
-
75
- state = stackerReducer(state, { type: "REMOVE", id: "ephemeral" });
76
- expect(state.items.map((i) => i.id)).toEqual(["next"]);
77
- expect(state.forcedKind).toBe("drawer");
78
-
79
- state = stackerReducer(state, { type: "REMOVE", id: "next" });
80
- expect(state.forcedKind).toBeNull();
81
- });
82
-
83
- it("does not lock kind when the founding overlay has no variant", () => {
84
- const state = open(STACKER_INITIAL_STATE, "a");
85
- expect(state.forcedKind).toBeNull();
86
- });
87
-
88
- it("closes every open item with CLOSE_ALL", () => {
89
- let state = open(STACKER_INITIAL_STATE, "a");
90
- state = open(state, "b");
91
- const closed = stackerReducer(state, { type: "CLOSE_ALL" });
92
- expect(closed.items.every((i) => !i.opened)).toBe(true);
93
- expect(stackerReducer(closed, { type: "CLOSE_ALL" })).toBe(closed);
94
- });
95
-
96
- it("merges settings on UPDATE", () => {
97
- const state = open(STACKER_INITIAL_STATE, "a");
98
- const updated = stackerReducer(state, {
99
- type: "UPDATE",
100
- id: "a",
101
- patch: { title: "renamed", withCloseButton: false },
102
- });
103
- expect(updated.items[0].settings.title).toBe("renamed");
104
- expect(updated.items[0].settings.withCloseButton).toBe(false);
105
- expect(stackerReducer(state, { type: "UPDATE", id: "missing", patch: {} })).toBe(state);
106
- });
107
- });
@@ -1,63 +0,0 @@
1
- import { getLanguageName, getLanguageParser } from "@src/syntax/language";
2
- import { describe, expect, it } from "vitest";
3
-
4
- /**
5
- * Counts the error nodes a registered language produces for a source snippet.
6
- * A clean parse is the prerequisite for any highlighting at all, so this is
7
- * the cheapest signal that a grammar is configured for the syntax it claims
8
- * to support.
9
- */
10
- function errorCount(language: string, source: string): number {
11
- const parser = getLanguageParser(language);
12
-
13
- if (!parser) {
14
- throw new Error(`No parser registered for "${language}"`);
15
- }
16
-
17
- let errors = 0;
18
-
19
- parser.parse(source).iterate({
20
- enter: (node) => {
21
- if (node.type.isError) errors++;
22
- },
23
- });
24
-
25
- return errors;
26
- }
27
-
28
- const TSX_SOURCE = `export function Greeting({ name }: { name: string }) {
29
- return <View><Text>{name}</Text></View>;
30
- }`;
31
-
32
- const TS_SOURCE = `interface User { id: string; age?: number }
33
- const user: User = { id: "a" };`;
34
-
35
- const JS_SOURCE = `const ok = a < b && c > d;
36
- const shifted = (n) => n << 2 > 1;`;
37
-
38
- describe("language registry", () => {
39
- it("registers tsx and jsx", () => {
40
- expect(getLanguageParser("tsx")).toBeDefined();
41
- expect(getLanguageParser("jsx")).toBeDefined();
42
- });
43
-
44
- it("resolves tsx and jsx to their base language names", () => {
45
- expect(getLanguageName("tsx")).toBe("TypeScript");
46
- expect(getLanguageName("jsx")).toBe("JavaScript");
47
- });
48
-
49
- it("parses JSX under jsx and tsx", () => {
50
- expect(errorCount("jsx", "const a = <View><Text>hi</Text></View>;")).toBe(0);
51
- expect(errorCount("tsx", TSX_SOURCE)).toBe(0);
52
- });
53
-
54
- it("parses TypeScript syntax under ts and tsx", () => {
55
- expect(errorCount("ts", TS_SOURCE)).toBe(0);
56
- expect(errorCount("tsx", TS_SOURCE)).toBe(0);
57
- });
58
-
59
- it("does not misread comparison operators as JSX in plain JavaScript", () => {
60
- expect(errorCount("js", JS_SOURCE)).toBe(0);
61
- expect(errorCount("ts", JS_SOURCE)).toBe(0);
62
- });
63
- });
@@ -1,143 +0,0 @@
1
- [
2
- {
3
- "uiKitFileName": "Memory",
4
- "symbolId": "25796:1314",
5
- "exportNodeId": "21128:24795",
6
- "figmaVectorName": "Memory_vector",
7
- "figmaFrameName": "Memory"
8
- },
9
- {
10
- "uiKitFileName": "Compute",
11
- "symbolId": "29295:58314",
12
- "exportNodeId": "29295:58314",
13
- "figmaVectorName": "Memory_vector",
14
- "figmaFrameName": "Memory",
15
- "figmaLightNodeId": "29295:58316"
16
- },
17
- {
18
- "uiKitFileName": "HealthChat",
19
- "symbolId": "25796:1395",
20
- "exportNodeId": "21128:25857",
21
- "figmaVectorName": "Chatbot_vector",
22
- "figmaFrameName": "Chatbot"
23
- },
24
- {
25
- "uiKitFileName": "Binary",
26
- "symbolId": "25796:1513",
27
- "exportNodeId": "25796:1513",
28
- "figmaVectorName": "Code blob (JSON)_vector",
29
- "figmaFrameName": "Code blob (JSON)",
30
- "figmaLightNodeId": "25796:2418"
31
- },
32
- {
33
- "uiKitFileName": "Clock",
34
- "symbolId": "25796:1318",
35
- "exportNodeId": "25796:1318",
36
- "figmaVectorName": "Flexible_vector",
37
- "figmaFrameName": "Flexible",
38
- "figmaLightNodeId": "25796:2536"
39
- },
40
- {
41
- "uiKitFileName": "CommitQueue",
42
- "symbolId": "25796:1323",
43
- "exportNodeId": "25796:1323",
44
- "figmaVectorName": "Hands On_vector",
45
- "figmaFrameName": "Hands On",
46
- "figmaLightNodeId": "25796:2600"
47
- },
48
- {
49
- "uiKitFileName": "Expand",
50
- "symbolId": "25796:1502",
51
- "exportNodeId": "25796:1502",
52
- "figmaVectorName": "Scale_vector",
53
- "figmaFrameName": "Scale",
54
- "figmaLightNodeId": "25796:2001"
55
- },
56
- {
57
- "uiKitFileName": "Swatch",
58
- "symbolId": "25796:1413",
59
- "exportNodeId": "25796:1413",
60
- "figmaVectorName": "Palette_vector",
61
- "figmaFrameName": "Palette",
62
- "figmaLightNodeId": "25796:3530"
63
- },
64
- {
65
- "uiKitFileName": "File",
66
- "symbolId": "25796:1511",
67
- "exportNodeId": "21128:25051",
68
- "figmaVectorName": "Document_vector",
69
- "figmaFrameName": "Document",
70
- "figmaLightNodeId": "25796:2030"
71
- },
72
- {
73
- "uiKitFileName": "Document",
74
- "symbolId": "25796:1375",
75
- "exportNodeId": "25796:1375",
76
- "figmaVectorName": "Document_vector",
77
- "figmaFrameName": "Document",
78
- "figmaLightNodeId": "25796:2030"
79
- },
80
- {
81
- "uiKitFileName": "Learn",
82
- "symbolId": "25796:1493",
83
- "exportNodeId": "21128:25729",
84
- "figmaVectorName": "Learn_vector",
85
- "figmaFrameName": "Learn",
86
- "figmaLightNodeId": "25796:2836"
87
- },
88
- {
89
- "uiKitFileName": "Tutorials",
90
- "symbolId": "25796:1397",
91
- "exportNodeId": "21128:25910",
92
- "figmaVectorName": "Chat Heart_vector",
93
- "figmaFrameName": "tutorials",
94
- "figmaLightNodeId": "25796:2725"
95
- },
96
- {
97
- "uiKitFileName": "MediaFile",
98
- "symbolId": "25796:1452",
99
- "exportNodeId": "25796:1452",
100
- "figmaVectorName": "Video file_vector",
101
- "figmaFrameName": "Video file",
102
- "figmaLightNodeId": "25796:2498"
103
- },
104
- {
105
- "uiKitFileName": "MergeQueue",
106
- "symbolId": "25796:1356",
107
- "exportNodeId": "25796:1356",
108
- "figmaVectorName": "Flexible_vector",
109
- "figmaFrameName": "Merge queue",
110
- "figmaLightNodeId": "25796:3507"
111
- },
112
- {
113
- "uiKitFileName": "Monitoring",
114
- "symbolId": "25796:1527",
115
- "exportNodeId": "25796:1527",
116
- "figmaVectorName": "_vector",
117
- "figmaFrameName": "Monitoring",
118
- "figmaLightNodeId": "25796:3056"
119
- },
120
- {
121
- "uiKitFileName": "Sun",
122
- "symbolId": "25796:1363",
123
- "exportNodeId": "25796:1363",
124
- "figmaVectorName": "Union_vector",
125
- "figmaFrameName": "Sun",
126
- "figmaLightNodeId": "25796:3526"
127
- },
128
- {
129
- "uiKitFileName": "Timeline",
130
- "symbolId": "25796:1365",
131
- "exportNodeId": "25796:1365",
132
- "figmaVectorName": "Bars_vector",
133
- "figmaFrameName": "Bars"
134
- },
135
- {
136
- "uiKitFileName": "HealthBubble",
137
- "symbolId": "25796:1366",
138
- "exportNodeId": "21128:26006",
139
- "figmaVectorName": "Health Chat_vector",
140
- "figmaFrameName": "Health Bubble",
141
- "figmaLightNodeId": "25796:3522"
142
- }
143
- ]
@@ -1,8 +0,0 @@
1
- [
2
- {
3
- "uiKitFileName": "Cursor",
4
- "exportNodeId": "25755:47884",
5
- "figmaFrameName": "Cursor",
6
- "figmaLightName": "Cursor_light"
7
- }
8
- ]
@@ -1,78 +0,0 @@
1
- import { execSync } from "node:child_process";
2
- import { exists, mkdtemp, readdir, readFile, rm, writeFile } from "node:fs/promises";
3
- import { tmpdir } from "node:os";
4
- import { join, parse } from "node:path";
5
-
6
- import { JSDOM } from "jsdom";
7
- import { optimize } from "svgo";
8
-
9
- if (!Bun.which("picosvg")) {
10
- console.error(
11
- "🚨 picosvg is not installed. Please install it: https://github.com/googlefonts/picosvg",
12
- );
13
- process.exit(1);
14
- }
15
-
16
- if (!(await exists("icons.zip"))) {
17
- console.error("🚨 icons.zip is not found. Please place it in the root of the project");
18
- process.exit(2);
19
- }
20
-
21
- const iconsDir = await mkdtemp(join(tmpdir(), "icons-"));
22
- const interDir = await mkdtemp(join(tmpdir(), "inter-"));
23
-
24
- // Unzip the icons.zip file
25
- try {
26
- execSync(`unzip icons.zip -d "${iconsDir}"`);
27
- } catch (error) {
28
- console.error("Error unzipping icons.zip:", error.message);
29
- }
30
-
31
- // Read all SVG files in the icons directory
32
- const files = (await readdir(iconsDir)).filter((file) => file.endsWith(".svg")).sort();
33
-
34
- let bundleCode = "// Generated by SurrealDB UI Kit. Do not modify manually.\n\n";
35
- let pureCode = "// Generated by SurrealDB UI Kit. Do not modify manually.\n\n";
36
-
37
- for (const file of files) {
38
- const inputPath = join(iconsDir, file);
39
- const outputPath = join(interDir, file);
40
- execSync(`picosvg "${inputPath}" --output_file "${outputPath}"`);
41
-
42
- const { name } = parse(file);
43
- const svg = await readFile(outputPath, "utf8");
44
- const optimized = optimize(svg, {
45
- multipass: true,
46
- plugins: [
47
- {
48
- name: "mergePaths",
49
- params: {
50
- force: true,
51
- noSpaceAfterFlags: false,
52
- },
53
- },
54
- ],
55
- }).data;
56
-
57
- const dom = new JSDOM(optimized);
58
- const paths = dom.window.document.querySelectorAll("path");
59
-
60
- if (paths.length !== 1) {
61
- throw new Error(`Icon ${name} has ${paths.length} paths, expected 1`);
62
- }
63
-
64
- const iconPath = paths[0].getAttribute("d");
65
-
66
- bundleCode += `export const icon${name}: string = "${iconPath}";\n`;
67
- pureCode += `export { icon${name} as ${name} } from "./icons";\n`;
68
-
69
- console.log(`🔄 Converted ${name}`);
70
- }
71
-
72
- await writeFile("./src/constants/icons.ts", bundleCode);
73
- await writeFile("./src/constants/icons-pure.ts", pureCode);
74
-
75
- console.log("✅ Updated icons.ts and icons-pure.ts!");
76
-
77
- await rm(iconsDir, { recursive: true });
78
- await rm(interDir, { recursive: true });
@@ -1,57 +0,0 @@
1
- [
2
- { "uiKitFileName": "Sidekick", "exportNodeId": "22777:30583", "figmaFrameName": "Sidekick" },
3
- { "uiKitFileName": "Development", "exportNodeId": "25796:1453", "figmaFrameName": "Settings" },
4
- {
5
- "uiKitFileName": "CloudNodes",
6
- "exportNodeId": "25796:1426",
7
- "figmaFrameName": "cloud nodes"
8
- },
9
- { "uiKitFileName": "Bot", "exportNodeId": "25796:1428", "figmaFrameName": "Agent / Bot" },
10
- { "uiKitFileName": "Agno", "exportNodeId": "21128:26168", "figmaFrameName": "Agno" },
11
- { "uiKitFileName": "Claude", "exportNodeId": "21128:26209", "figmaFrameName": "Claude" },
12
- { "uiKitFileName": "GitHub", "exportNodeId": "21128:26223", "figmaFrameName": "GitHub" },
13
- { "uiKitFileName": "Medium", "exportNodeId": "21128:26218", "figmaFrameName": "Medium" },
14
- { "uiKitFileName": "LangChain", "exportNodeId": "21128:26198", "figmaFrameName": "LangChain" },
15
- { "uiKitFileName": "Reddit", "exportNodeId": "21128:26190", "figmaFrameName": "Reddit" },
16
- { "uiKitFileName": "X", "exportNodeId": "21128:26194", "figmaFrameName": "X" },
17
- { "uiKitFileName": "MCP", "exportNodeId": "24452:1002", "figmaFrameName": "MCP" },
18
- { "uiKitFileName": "RAG", "exportNodeId": "21128:26228", "figmaFrameName": "RAG" },
19
- { "uiKitFileName": "Windsurf", "exportNodeId": "21128:26240", "figmaFrameName": "Windsurf" },
20
- { "uiKitFileName": "Instagram", "exportNodeId": "21128:26248", "figmaFrameName": "Instagram" },
21
- { "uiKitFileName": "Discord", "exportNodeId": "21128:26252", "figmaFrameName": "Discord" },
22
- { "uiKitFileName": "Zapier", "exportNodeId": "21128:26256", "figmaFrameName": "Zapier" },
23
- { "uiKitFileName": "Python", "exportNodeId": "21128:26096", "figmaFrameName": "Python" },
24
- { "uiKitFileName": "Cline", "exportNodeId": "21128:26114", "figmaFrameName": "Cline" },
25
- { "uiKitFileName": "Dev", "exportNodeId": "21128:26118", "figmaFrameName": "Dev" },
26
- { "uiKitFileName": "Rust", "exportNodeId": "21128:24875", "figmaFrameName": "Rust" },
27
- { "uiKitFileName": "Threads", "exportNodeId": "21128:26146", "figmaFrameName": "Threads" },
28
- { "uiKitFileName": "Zed", "exportNodeId": "21128:26150", "figmaFrameName": "Zed" },
29
- {
30
- "uiKitFileName": "StackOverflow",
31
- "exportNodeId": "21128:26164",
32
- "figmaFrameName": "Stack Overflow"
33
- },
34
- { "uiKitFileName": "LinkedIn", "exportNodeId": "21128:26270", "figmaFrameName": "LinkedIn" },
35
- { "uiKitFileName": "Youtube", "exportNodeId": "21128:26274", "figmaFrameName": "YouTube" },
36
- { "uiKitFileName": "N8n", "exportNodeId": "21128:26131", "figmaFrameName": "n8n" },
37
- { "uiKitFileName": "Wasm", "exportNodeId": "21128:26139", "figmaFrameName": "WebAssembly" },
38
- {
39
- "uiKitFileName": "VisualStudioCode",
40
- "exportNodeId": "21128:26178",
41
- "figmaFrameName": "Visual Studio Code"
42
- },
43
- { "uiKitFileName": "PDF", "exportNodeId": "25796:1324", "figmaFrameName": "Document / PDF" },
44
- {
45
- "uiKitFileName": "Javascript",
46
- "exportNodeId": "23768:22323",
47
- "figmaFrameName": "Javascript"
48
- },
49
- { "uiKitFileName": "OpenAI", "exportNodeId": "24452:982", "figmaFrameName": "OpenAI" },
50
- {
51
- "uiKitFileName": "SurrealMCP",
52
- "exportNodeId": "24452:1007",
53
- "figmaFrameName": "MCP"
54
- },
55
- { "uiKitFileName": "SurrealML", "exportNodeId": "25433:6610", "figmaFrameName": "SurrealML" },
56
- { "uiKitFileName": "YUApp", "exportNodeId": "21128:24571", "figmaFrameName": "YU app" }
57
- ]
@@ -1,64 +0,0 @@
1
- /**
2
- * Compare Figma light exports against existing ui-kit pictos using perceptual hash.
3
- * Used to validate the picto-figma-map.json name mappings.
4
- *
5
- * Usage:
6
- * bun tools/picto-compare.ts <urls-manifest.json>
7
- *
8
- * Manifest format: [{ fileName: "PadlockClosed", nodeId, url }] for light versions
9
- */
10
-
11
- import { execSync } from "node:child_process";
12
- import { mkdir, readFile, writeFile } from "node:fs/promises";
13
- import { join } from "node:path";
14
-
15
- const PICTOS_DIR = join(import.meta.dir, "../src/assets/pictos");
16
- const TMP = join(import.meta.dir, "../.picto-compare");
17
-
18
- async function phash(path: string): Promise<string> {
19
- return execSync(`magick "${path}" -colorspace Gray -resize 16x16! -depth 8 txt:-`, {
20
- encoding: "utf8",
21
- });
22
- }
23
-
24
- function hashDistance(a: string, b: string): number {
25
- const valsA = [...a.matchAll(/\\((\\d+),(\\d+)\\)\\s+#(\\w+)/g)].map((m) =>
26
- Number.parseInt(m[3], 16),
27
- );
28
- const valsB = [...b.matchAll(/\\((\\d+),(\\d+)\\)\\s+#(\\w+)/g)].map((m) =>
29
- Number.parseInt(m[3], 16),
30
- );
31
- let dist = 0;
32
- for (let i = 0; i < Math.min(valsA.length, valsB.length); i++) {
33
- dist += Math.abs(valsA[i] - valsB[i]);
34
- }
35
- return dist;
36
- }
37
-
38
- async function main() {
39
- const manifest: { fileName: string; url: string }[] = JSON.parse(
40
- await readFile(process.argv[2], "utf8"),
41
- );
42
- await mkdir(TMP, { recursive: true });
43
-
44
- const results: { fileName: string; distance: number; matched: boolean }[] = [];
45
-
46
- for (const { fileName, url } of manifest) {
47
- const figmaPng = join(TMP, `${fileName}-figma.png`);
48
- const res = await fetch(url);
49
- await writeFile(figmaPng, await res.arrayBuffer());
50
-
51
- const repoWebp = join(PICTOS_DIR, `${fileName}.webp`);
52
- const repoPng = join(TMP, `${fileName}-repo.png`);
53
- execSync(`magick "${repoWebp}" "${repoPng}"`);
54
-
55
- const dist = hashDistance(await phash(figmaPng), await phash(repoPng));
56
- results.push({ fileName, distance: dist, matched: dist < 5000 });
57
- }
58
-
59
- const failed = results.filter((r) => !r.matched);
60
- console.log(`Compared ${results.length}, mismatches: ${failed.length}`);
61
- for (const f of failed) console.log(` ${f.fileName}: distance ${f.distance}`);
62
- }
63
-
64
- main().catch(console.error);
@@ -1,43 +0,0 @@
1
- /** Merge partial/agent screenshot URL results into urls.json */
2
- import { readdir, readFile, writeFile } from "node:fs/promises";
3
- import { join } from "node:path";
4
-
5
- const PNG_DIR = join(import.meta.dir, "../.picto-gradient-png");
6
-
7
- const batchFiles = (await readdir(PNG_DIR))
8
- .filter((f) => f.startsWith("screenshot-batch-") && f.endsWith(".json"))
9
- .sort((a, b) => Number(a.match(/\d+/)?.[0]) - Number(b.match(/\d+/)?.[0]));
10
-
11
- const expected: { fileName: string; nodeId: string }[] = [];
12
- for (const f of batchFiles) {
13
- expected.push(...JSON.parse(await readFile(join(PNG_DIR, f), "utf8")));
14
- }
15
-
16
- const resultFiles = [
17
- "results-transparent-partial.json",
18
- "results-partial.json",
19
- ...(await readdir(PNG_DIR))
20
- .filter((f) => f.startsWith("results-agent-") && f.endsWith(".json"))
21
- .sort(),
22
- ];
23
-
24
- const byName = new Map<string, string>();
25
- for (const rf of resultFiles) {
26
- try {
27
- const entries: { fileName: string; url: string }[] = JSON.parse(
28
- await readFile(join(PNG_DIR, rf), "utf8"),
29
- );
30
- for (const e of entries) byName.set(e.fileName, e.url);
31
- } catch {
32
- // file may not exist yet
33
- }
34
- }
35
-
36
- const urls = expected.map(({ fileName }) => {
37
- const url = byName.get(fileName);
38
- if (!url) throw new Error(`Missing URL for ${fileName}`);
39
- return { fileName, url };
40
- });
41
-
42
- await writeFile(join(PNG_DIR, "urls.json"), `${JSON.stringify(urls, null, 2)}\n`);
43
- console.log(`Merged ${urls.length} entries into urls.json`);