@surrealdb/ui 1.2.15 → 1.2.17

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 (148) 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/ui.d.ts +12 -0
  8. package/dist/ui.js +678 -649
  9. package/dist/ui.js.map +1 -1
  10. package/package.json +8 -2
  11. package/.claude/launch.json +0 -17
  12. package/.oxfmtrc.json +0 -27
  13. package/.oxlintrc.json +0 -23
  14. package/.picto-fix-png/Cursor.png +0 -0
  15. package/.picto-fix-png/DocumentGradient.png +0 -0
  16. package/.picto-fix-png/FileGradient.png +0 -0
  17. package/.picto-fix-png/HealthBubbleGradient.png +0 -0
  18. package/.picto-fix-png/LearnGradient.png +0 -0
  19. package/.picto-fix-png/MediaFileGradient.png +0 -0
  20. package/.zed/settings.json +0 -36
  21. package/AGENTS.md +0 -111
  22. package/CLAUDE.md +0 -111
  23. package/REVIEW.md +0 -81
  24. package/doc/code-style.md +0 -264
  25. package/doc/release.md +0 -102
  26. package/doc/stacker-plan.md +0 -219
  27. package/release-notes.md +0 -0
  28. package/tests/_setup/e2e-helpers.tsx +0 -169
  29. package/tests/_setup/markdown-classes.ts +0 -3
  30. package/tests/_setup/portable-stories.ts +0 -33
  31. 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
  32. package/tests/e2e/MarkdownEditor/__screenshots__/content-blocks.test.tsx/MarkdownEditor---content-blocks-renders-a-diagram-for-the-fenced-mermaid-block-1.png +0 -0
  33. package/tests/e2e/MarkdownEditor/__screenshots__/content-blocks.test.tsx/MarkdownEditor---content-blocks-renders-a-horizontal-rule-as-a-separator-1.png +0 -0
  34. 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
  35. package/tests/e2e/MarkdownEditor/__screenshots__/content-blocks.test.tsx/MarkdownEditor---content-blocks-shows-blockquote-text-from-the-sample-document-1.png +0 -0
  36. package/tests/e2e/MarkdownEditor/__screenshots__/content-blocks.test.tsx/MarkdownEditor---content-blocks-shows-fenced-TypeScript-sample-code-in-the-document-1.png +0 -0
  37. 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
  38. 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
  39. package/tests/e2e/MarkdownEditor/__screenshots__/edits.test.tsx/MarkdownEditor---edits-reflects-typed-characters-in-the-underlying-document-1.png +0 -0
  40. 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
  41. 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
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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
  54. 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
  55. 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
  56. 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
  57. package/tests/e2e/MarkdownEditor/__screenshots__/media-sizing.test.tsx/MarkdownEditor---media-sizing-matches-MarkdownViewer-image-width-in-the-split-playground-1.png +0 -0
  58. package/tests/e2e/MarkdownEditor/__screenshots__/modes.test.tsx/MarkdownEditor---modes-standalone-MarkdownViewer-is-not-a-CodeMirror-surface-1.png +0 -0
  59. package/tests/e2e/MarkdownEditor/__screenshots__/modes.test.tsx/MarkdownEditor---modes-toggling-the-SegmentedControl-swaps-mode-without-remounting-the-editor-1.png +0 -0
  60. package/tests/e2e/MarkdownEditor/__screenshots__/regressions.test.tsx/MarkdownEditor---regressions-repeated-checkbox-toggles-do-not-duplicate-or-drift-task-markers-1.png +0 -0
  61. 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
  62. 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
  63. 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
  64. 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
  65. 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
  66. 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
  67. package/tests/e2e/MarkdownEditor/__screenshots__/undo-redo.test.tsx/MarkdownEditor---undo-and-redo-restores-undone-document-edits-via-redo-1.png +0 -0
  68. package/tests/e2e/MarkdownEditor/content-blocks.test.tsx +0 -153
  69. package/tests/e2e/MarkdownEditor/edits.test.tsx +0 -112
  70. package/tests/e2e/MarkdownEditor/heading-fold.test.tsx +0 -45
  71. package/tests/e2e/MarkdownEditor/hybrid-widgets.test.tsx +0 -193
  72. package/tests/e2e/MarkdownEditor/image-on-image.test.tsx +0 -73
  73. package/tests/e2e/MarkdownEditor/jsx-block-content.test.tsx +0 -243
  74. package/tests/e2e/MarkdownEditor/jsx-highlight.test.tsx +0 -69
  75. package/tests/e2e/MarkdownEditor/jsx-inline-badges.test.tsx +0 -60
  76. package/tests/e2e/MarkdownEditor/jsx-inline-click.test.tsx +0 -54
  77. package/tests/e2e/MarkdownEditor/jsx-selection.test.tsx +0 -44
  78. package/tests/e2e/MarkdownEditor/link-placeholder.test.tsx +0 -68
  79. package/tests/e2e/MarkdownEditor/media-align.test.tsx +0 -58
  80. package/tests/e2e/MarkdownEditor/media-edit.test.tsx +0 -64
  81. package/tests/e2e/MarkdownEditor/media-sizing.test.tsx +0 -124
  82. package/tests/e2e/MarkdownEditor/modes.test.tsx +0 -94
  83. package/tests/e2e/MarkdownEditor/onimage-parity.test.tsx +0 -50
  84. package/tests/e2e/MarkdownEditor/regressions.test.tsx +0 -223
  85. package/tests/e2e/MarkdownEditor/slash-commands.test.tsx +0 -100
  86. package/tests/e2e/MarkdownEditor/table-click.test.tsx +0 -48
  87. package/tests/e2e/MarkdownEditor/table-controls.test.tsx +0 -57
  88. package/tests/e2e/MarkdownEditor/table-format.test.tsx +0 -42
  89. package/tests/e2e/MarkdownEditor/undo-redo.test.tsx +0 -39
  90. package/tests/e2e/MarkdownViewer/__screenshots__/parity.test.tsx/MarkdownViewer---editor-parity-matches-computed-font-size-on-first-heading-1.png +0 -0
  91. package/tests/e2e/MarkdownViewer/__screenshots__/parity.test.tsx/MarkdownViewer---editor-parity-matches-counts-for-shared-structural-classes-1.png +0 -0
  92. package/tests/e2e/MarkdownViewer/__screenshots__/parity.test.tsx/MarkdownViewer---editor-parity-matches-visible-text-between-preview-editor--blurred--and-MarkdownViewer-1.png +0 -0
  93. package/tests/e2e/MarkdownViewer/__screenshots__/render.test.tsx/MarkdownViewer---render-exercises-shared-preview-class-names-without-mounting-CodeMirror-1.png +0 -0
  94. package/tests/e2e/MarkdownViewer/parity.test.tsx +0 -191
  95. package/tests/e2e/MarkdownViewer/render.test.tsx +0 -36
  96. package/tests/e2e/Stacker/stacker.test.tsx +0 -304
  97. package/tests/unit/Editor/helpers.test.ts +0 -42
  98. package/tests/unit/MarkdownConformance/error-isolation.test.tsx +0 -44
  99. package/tests/unit/MarkdownConformance/indentation.test.tsx +0 -30
  100. package/tests/unit/MarkdownConformance/inline-code-fuzz.test.tsx +0 -255
  101. package/tests/unit/MarkdownConformance/jsx-attributes.test.tsx +0 -57
  102. package/tests/unit/MarkdownConformance/jsx-fuzz.test.tsx +0 -165
  103. package/tests/unit/MarkdownConformance/links.test.tsx +0 -95
  104. package/tests/unit/MarkdownConformance/render-helpers.tsx +0 -88
  105. package/tests/unit/MarkdownEditor/code-info.test.ts +0 -63
  106. package/tests/unit/MarkdownEditor/decorations.test.ts +0 -490
  107. package/tests/unit/MarkdownEditor/editor-ready.test.ts +0 -36
  108. package/tests/unit/MarkdownEditor/html-descriptors.test.ts +0 -94
  109. package/tests/unit/MarkdownEditor/indented-fence.test.ts +0 -103
  110. package/tests/unit/MarkdownEditor/jsx-attr-scan.test.ts +0 -115
  111. package/tests/unit/MarkdownEditor/jsx-block-widget.test.ts +0 -92
  112. package/tests/unit/MarkdownEditor/jsx-tag-grammar.test.ts +0 -88
  113. package/tests/unit/MarkdownEditor/list-indent.test.ts +0 -95
  114. package/tests/unit/MarkdownEditor/slash-commands.test.ts +0 -213
  115. package/tests/unit/MarkdownEditor/table-format.test.ts +0 -83
  116. package/tests/unit/MarkdownEditor/table.test.ts +0 -119
  117. package/tests/unit/MarkdownEditor/triggers.test.ts +0 -244
  118. package/tests/unit/MarkdownEditor/widget-store.test.ts +0 -105
  119. package/tests/unit/MarkdownViewer/callout.test.tsx +0 -60
  120. package/tests/unit/MarkdownViewer/code-highlight.test.tsx +0 -61
  121. package/tests/unit/MarkdownViewer/code-title.test.tsx +0 -62
  122. package/tests/unit/MarkdownViewer/features.test.tsx +0 -164
  123. package/tests/unit/MarkdownViewer/headings.test.tsx +0 -40
  124. package/tests/unit/MarkdownViewer/indented-jsx-children.test.tsx +0 -98
  125. package/tests/unit/MarkdownViewer/jsx-block-nesting.test.tsx +0 -234
  126. package/tests/unit/MarkdownViewer/jsx.test.tsx +0 -211
  127. package/tests/unit/MarkdownViewer/list-bullets.test.tsx +0 -49
  128. package/tests/unit/MarkdownViewer/list-code.test.tsx +0 -65
  129. package/tests/unit/MarkdownViewer/preserve-newlines.test.tsx +0 -143
  130. package/tests/unit/MarkdownViewer/read-time.test.ts +0 -21
  131. package/tests/unit/MarkdownViewer/renderers.test.tsx +0 -95
  132. package/tests/unit/MarkdownViewer/runnable.test.tsx +0 -69
  133. package/tests/unit/MarkdownViewer/ssr.test.tsx +0 -94
  134. package/tests/unit/MarkdownViewer/syntax-highlighting.test.tsx +0 -74
  135. package/tests/unit/MarkdownViewer/tabs-fenced-code.test.tsx +0 -196
  136. package/tests/unit/MarkdownViewer/tabs.test.tsx +0 -116
  137. package/tests/unit/Stacker/drag.test.ts +0 -21
  138. package/tests/unit/Stacker/helpers.test.ts +0 -105
  139. package/tests/unit/Stacker/reducer.test.ts +0 -107
  140. package/tools/duplicate-vector-mappings.json +0 -143
  141. package/tools/glass-export-overrides.json +0 -8
  142. package/tools/icon-parser.ts +0 -78
  143. package/tools/integration-gradient-exports.json +0 -57
  144. package/tools/picto-compare.ts +0 -64
  145. package/tools/picto-merge-urls.ts +0 -43
  146. package/tools/picto-sync.ts +0 -630
  147. package/tools/picto-verify-gradients.ts +0 -86
  148. 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,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`);