@redocly/theme 0.61.0 → 0.62.0-custom.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/lib/components/Admonition/Admonition.js +14 -18
  2. package/lib/components/Admonition/variables.dark.d.ts +1 -0
  3. package/lib/components/Admonition/variables.dark.js +18 -0
  4. package/lib/components/Admonition/variables.js +24 -28
  5. package/lib/components/AsyncApiDocs/hooks/AfterAsyncApiChannelDescription.d.ts +1 -0
  6. package/lib/components/AsyncApiDocs/hooks/AfterAsyncApiChannelDescription.js +12 -0
  7. package/lib/components/Badge/Badge.d.ts +2 -1
  8. package/lib/components/Badge/Badge.js +24 -2
  9. package/lib/components/Banner/Banner.js +19 -1
  10. package/lib/components/Banner/variables.js +1 -0
  11. package/lib/components/Breadcrumbs/Breadcrumb.js +1 -1
  12. package/lib/components/Breadcrumbs/BreadcrumbDropdown.js +9 -6
  13. package/lib/components/Breadcrumbs/Breadcrumbs.js +24 -15
  14. package/lib/components/Buttons/AIAssistantButton.js +7 -4
  15. package/lib/components/Catalog/CatalogEntities.js +10 -8
  16. package/lib/components/Catalog/CatalogEntity/CatalogEntity.js +2 -2
  17. package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.js +5 -3
  18. package/lib/components/Catalog/CatalogEntity/CatalogEntityProperties/TagsProperty.js +2 -2
  19. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable.js +13 -11
  20. package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +7 -5
  21. package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.js +9 -7
  22. package/lib/components/Catalog/CatalogTableView/CatalogTableViewRow.js +1 -1
  23. package/lib/components/Catalog/CatalogTagsWithTooltip.js +2 -2
  24. package/lib/components/CatalogClassic/CatalogClassicInfoBlock.js +1 -1
  25. package/lib/components/CodeBlock/CodeBlockControls.js +8 -6
  26. package/lib/components/Filter/FilterCheckboxes.js +1 -1
  27. package/lib/components/JsonViewer/JsonViewer.js +2 -2
  28. package/lib/components/JsonViewer/{Helpers.js → helpers.js} +2 -1
  29. package/lib/components/LanguagePicker/LanguagePicker.js +1 -1
  30. package/lib/components/Markdown/Markdown.js +2 -2
  31. package/lib/components/Menu/MenuItem.js +41 -15
  32. package/lib/components/Navbar/NavbarItem.js +1 -1
  33. package/lib/components/OpenApiDocs/hooks/AdditionalOverviewInfo.d.ts +1 -0
  34. package/lib/components/OpenApiDocs/hooks/AdditionalOverviewInfo.js +12 -0
  35. package/lib/components/OpenApiDocs/hooks/AfterOpenApiDescription.d.ts +1 -0
  36. package/lib/components/OpenApiDocs/hooks/AfterOpenApiDescription.js +6 -0
  37. package/lib/components/PageActions/PageActions.js +25 -8
  38. package/lib/components/Search/SearchAiDialog.d.ts +4 -2
  39. package/lib/components/Search/SearchAiDialog.js +23 -4
  40. package/lib/components/Search/SearchAiMessage.d.ts +4 -2
  41. package/lib/components/Search/SearchAiMessage.js +82 -23
  42. package/lib/components/Search/SearchDialog.js +50 -25
  43. package/lib/components/Select/variables.js +2 -2
  44. package/lib/components/SvgViewer/SvgViewer.d.ts +15 -0
  45. package/lib/components/SvgViewer/SvgViewer.js +312 -0
  46. package/lib/components/SvgViewer/variables.d.ts +1 -0
  47. package/lib/components/SvgViewer/variables.dark.d.ts +1 -0
  48. package/lib/components/SvgViewer/variables.dark.js +8 -0
  49. package/lib/components/SvgViewer/variables.js +17 -0
  50. package/lib/components/Tag/Tag.js +1 -1
  51. package/lib/components/Tag/variables.dark.js +6 -0
  52. package/lib/components/Tag/variables.js +6 -0
  53. package/lib/components/Tooltip/Tooltip.d.ts +2 -3
  54. package/lib/components/Tooltip/Tooltip.js +66 -113
  55. package/lib/components/Tooltip/variables.dark.js +4 -0
  56. package/lib/components/Tooltip/variables.js +3 -3
  57. package/lib/components/UserMenu/LoginButton.d.ts +8 -2
  58. package/lib/components/UserMenu/LoginButton.js +4 -3
  59. package/lib/core/constants/search.d.ts +5 -1
  60. package/lib/core/constants/search.js +24 -1
  61. package/lib/core/hooks/search/use-search-dialog.js +2 -2
  62. package/lib/core/hooks/use-color-switcher.d.ts +1 -0
  63. package/lib/core/hooks/use-color-switcher.js +8 -1
  64. package/lib/core/hooks/use-mcp-config.js +2 -1
  65. package/lib/core/hooks/use-modal-scroll-lock.js +24 -10
  66. package/lib/core/hooks/use-outside-click.d.ts +3 -1
  67. package/lib/core/hooks/use-outside-click.js +8 -4
  68. package/lib/core/hooks/use-page-actions.d.ts +1 -1
  69. package/lib/core/hooks/use-page-actions.js +44 -11
  70. package/lib/core/hooks/use-product-picker.js +1 -1
  71. package/lib/core/hooks/use-unique-svg-ids.d.ts +6 -0
  72. package/lib/core/hooks/use-unique-svg-ids.js +15 -0
  73. package/lib/core/openapi/index.d.ts +1 -0
  74. package/lib/core/openapi/index.js +3 -1
  75. package/lib/core/styles/dark.js +4 -0
  76. package/lib/core/styles/global.js +31 -15
  77. package/lib/core/types/catalog.d.ts +1 -1
  78. package/lib/core/types/hooks.d.ts +23 -2
  79. package/lib/core/types/l10n.d.ts +1 -1
  80. package/lib/core/types/search.d.ts +24 -0
  81. package/lib/core/types/search.js +9 -1
  82. package/lib/core/utils/content-segments.d.ts +2 -0
  83. package/lib/core/utils/content-segments.js +22 -0
  84. package/lib/core/utils/index.d.ts +1 -0
  85. package/lib/core/utils/index.js +1 -0
  86. package/lib/core/utils/transform-revisions-to-version-history.js +8 -51
  87. package/lib/ext/process-scorecard.d.ts +5 -0
  88. package/lib/ext/process-scorecard.js +11 -0
  89. package/lib/icons/FitToViewIcon/FitToViewIcon.d.ts +9 -0
  90. package/lib/icons/FitToViewIcon/FitToViewIcon.js +25 -0
  91. package/lib/icons/WarningCycleIcon/WarningCycleIcon.d.ts +9 -0
  92. package/lib/icons/WarningCycleIcon/WarningCycleIcon.js +24 -0
  93. package/lib/index.d.ts +9 -0
  94. package/lib/index.js +9 -0
  95. package/lib/layouts/DocumentationLayout.js +4 -25
  96. package/lib/layouts/DocumentationLayoutBottom.d.ts +11 -0
  97. package/lib/layouts/DocumentationLayoutBottom.js +28 -0
  98. package/lib/layouts/DocumentationLayoutTop.d.ts +13 -0
  99. package/lib/layouts/DocumentationLayoutTop.js +33 -0
  100. package/lib/layouts/Forbidden.js +22 -18
  101. package/lib/markdoc/components/Cards/Card.js +1 -0
  102. package/lib/markdoc/components/CodeWalkthrough/CodeFilters.js +1 -1
  103. package/lib/markdoc/components/Heading/Heading.js +40 -2
  104. package/lib/markdoc/components/LoginButton/LoginButton.d.ts +9 -0
  105. package/lib/markdoc/components/LoginButton/LoginButton.js +48 -0
  106. package/lib/markdoc/components/Mermaid/Mermaid.js +70 -2
  107. package/lib/markdoc/components/default.d.ts +1 -0
  108. package/lib/markdoc/components/default.js +1 -0
  109. package/lib/markdoc/default.d.ts +6 -0
  110. package/lib/markdoc/default.js +2 -0
  111. package/lib/markdoc/tags/login-button.d.ts +2 -0
  112. package/lib/markdoc/tags/login-button.js +32 -0
  113. package/package.json +9 -9
  114. package/src/components/Admonition/Admonition.tsx +14 -18
  115. package/src/components/Admonition/variables.dark.ts +15 -0
  116. package/src/components/Admonition/variables.ts +24 -28
  117. package/src/components/AsyncApiDocs/hooks/AfterAsyncApiChannelDescription.tsx +10 -0
  118. package/src/components/Badge/Badge.tsx +18 -2
  119. package/src/components/Banner/Banner.tsx +23 -1
  120. package/src/components/Banner/variables.ts +1 -0
  121. package/src/components/Breadcrumbs/Breadcrumb.tsx +3 -3
  122. package/src/components/Breadcrumbs/BreadcrumbDropdown.tsx +11 -8
  123. package/src/components/Breadcrumbs/Breadcrumbs.tsx +24 -15
  124. package/src/components/Buttons/AIAssistantButton.tsx +7 -4
  125. package/src/components/Catalog/CatalogEntities.tsx +10 -8
  126. package/src/components/Catalog/CatalogEntity/CatalogEntity.tsx +1 -1
  127. package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.tsx +7 -4
  128. package/src/components/Catalog/CatalogEntity/CatalogEntityProperties/TagsProperty.tsx +1 -1
  129. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable.tsx +13 -11
  130. package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +7 -5
  131. package/src/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.tsx +9 -7
  132. package/src/components/Catalog/CatalogTableView/CatalogTableViewRow.tsx +1 -2
  133. package/src/components/Catalog/CatalogTagsWithTooltip.tsx +9 -5
  134. package/src/components/CatalogClassic/CatalogClassicInfoBlock.tsx +3 -1
  135. package/src/components/CodeBlock/CodeBlockControls.tsx +16 -10
  136. package/src/components/Filter/FilterCheckboxes.tsx +1 -1
  137. package/src/components/JsonViewer/JsonViewer.tsx +1 -2
  138. package/src/components/JsonViewer/{Helpers.tsx → helpers.tsx} +1 -0
  139. package/src/components/LanguagePicker/LanguagePicker.tsx +1 -1
  140. package/src/components/Markdown/Markdown.tsx +2 -2
  141. package/src/components/Menu/MenuItem.tsx +61 -16
  142. package/src/components/Navbar/NavbarItem.tsx +3 -1
  143. package/src/components/OpenApiDocs/hooks/AdditionalOverviewInfo.tsx +10 -0
  144. package/src/components/OpenApiDocs/hooks/AfterOpenApiDescription.tsx +2 -0
  145. package/src/components/PageActions/PageActions.tsx +38 -15
  146. package/src/components/Search/SearchAiDialog.tsx +31 -2
  147. package/src/components/Search/SearchAiMessage.tsx +103 -17
  148. package/src/components/Search/SearchDialog.tsx +70 -37
  149. package/src/components/Select/variables.ts +2 -2
  150. package/src/components/SvgViewer/SvgViewer.tsx +405 -0
  151. package/src/components/SvgViewer/variables.dark.ts +5 -0
  152. package/src/components/SvgViewer/variables.ts +14 -0
  153. package/src/components/Tag/Tag.tsx +2 -1
  154. package/src/components/Tag/variables.dark.ts +6 -0
  155. package/src/components/Tag/variables.ts +6 -0
  156. package/src/components/Tooltip/Tooltip.tsx +77 -120
  157. package/src/components/Tooltip/variables.dark.ts +4 -0
  158. package/src/components/Tooltip/variables.ts +3 -3
  159. package/src/components/UserMenu/LoginButton.tsx +23 -8
  160. package/src/core/constants/search.ts +27 -1
  161. package/src/core/hooks/__mocks__/use-theme-hooks.ts +10 -1
  162. package/src/core/hooks/search/use-search-dialog.ts +2 -2
  163. package/src/core/hooks/use-color-switcher.ts +10 -2
  164. package/src/core/hooks/use-mcp-config.ts +2 -1
  165. package/src/core/hooks/use-modal-scroll-lock.ts +29 -10
  166. package/src/core/hooks/use-outside-click.ts +16 -5
  167. package/src/core/hooks/use-page-actions.ts +66 -25
  168. package/src/core/hooks/use-product-picker.ts +1 -1
  169. package/src/core/hooks/use-unique-svg-ids.ts +12 -0
  170. package/src/core/openapi/index.ts +1 -0
  171. package/src/core/styles/dark.ts +4 -0
  172. package/src/core/styles/global.ts +31 -15
  173. package/src/core/types/catalog.ts +1 -1
  174. package/src/core/types/hooks.ts +29 -1
  175. package/src/core/types/l10n.ts +12 -1
  176. package/src/core/types/search.ts +19 -0
  177. package/src/core/utils/content-segments.ts +27 -0
  178. package/src/core/utils/index.ts +1 -0
  179. package/src/core/utils/transform-revisions-to-version-history.ts +8 -80
  180. package/src/ext/process-scorecard.ts +14 -0
  181. package/src/icons/FitToViewIcon/FitToViewIcon.tsx +26 -0
  182. package/src/icons/WarningCycleIcon/WarningCycleIcon.tsx +32 -0
  183. package/src/index.ts +9 -0
  184. package/src/layouts/DocumentationLayout.tsx +4 -30
  185. package/src/layouts/DocumentationLayoutBottom.tsx +42 -0
  186. package/src/layouts/DocumentationLayoutTop.tsx +52 -0
  187. package/src/layouts/Forbidden.tsx +36 -21
  188. package/src/markdoc/components/Cards/Card.tsx +1 -0
  189. package/src/markdoc/components/CodeWalkthrough/CodeFilters.tsx +1 -1
  190. package/src/markdoc/components/Heading/Heading.tsx +52 -4
  191. package/src/markdoc/components/LoginButton/LoginButton.tsx +38 -0
  192. package/src/markdoc/components/Mermaid/Mermaid.tsx +57 -8
  193. package/src/markdoc/components/default.ts +1 -0
  194. package/src/markdoc/default.ts +2 -0
  195. package/src/markdoc/tags/login-button.ts +30 -0
  196. package/lib/components/Tooltip/TooltipWrapper.d.ts +0 -12
  197. package/lib/components/Tooltip/TooltipWrapper.js +0 -34
  198. package/src/components/Tooltip/TooltipWrapper.tsx +0 -70
  199. /package/lib/components/JsonViewer/{Helpers.d.ts → helpers.d.ts} +0 -0
@@ -0,0 +1,405 @@
1
+ import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
2
+ import styled, { keyframes } from 'styled-components';
3
+
4
+ import type { JSX, TouchEvent as ReactTouchEvent, WheelEvent, MouseEvent, ReactNode } from 'react';
5
+
6
+ import { useModalScrollLock } from '@redocly/theme/core/hooks';
7
+ import { Button } from '@redocly/theme/components/Button/Button';
8
+ import { Tooltip } from '@redocly/theme/components/Tooltip/Tooltip';
9
+ import { AddIcon } from '@redocly/theme/icons/AddIcon/AddIcon';
10
+ import { SubtractIcon } from '@redocly/theme/icons/SubtractIcon/SubtractIcon';
11
+ import { CloseIcon } from '@redocly/theme/icons/CloseIcon/CloseIcon';
12
+ import { FitToViewIcon } from '@redocly/theme/icons/FitToViewIcon/FitToViewIcon';
13
+
14
+ export type SvgViewerLabels = {
15
+ zoomIn?: string;
16
+ zoomOut?: string;
17
+ fitToView?: string;
18
+ close?: string;
19
+ dialogLabel?: string;
20
+ };
21
+
22
+ export type SvgViewerProps = {
23
+ isOpen: boolean;
24
+ onClose: () => void;
25
+ children: ReactNode;
26
+ labels?: SvgViewerLabels;
27
+ };
28
+
29
+ type Position = { x: number; y: number };
30
+
31
+ const MIN_SCALE_FACTOR = 0.1;
32
+ const MAX_SCALE_FACTOR = 5;
33
+ const ZOOM_STEP = 0.1;
34
+ const WHEEL_SENSITIVITY = 0.002;
35
+ const VIEWPORT_PADDING = 60;
36
+ const FIT_SCALE_FACTOR = 0.9;
37
+
38
+ export function SvgViewer({
39
+ isOpen,
40
+ onClose,
41
+ children,
42
+ labels = {},
43
+ }: SvgViewerProps): JSX.Element | null {
44
+ const [scale, setScale] = useState(1);
45
+ const [baseScale, setBaseScale] = useState(1);
46
+ const [position, setPosition] = useState<Position>({ x: 0, y: 0 });
47
+ const [isDragging, setIsDragging] = useState(false);
48
+ const [dragStart, setDragStart] = useState<Position>({ x: 0, y: 0 });
49
+ const [pinchState, setPinchState] = useState<{ distance: number; scale: number } | null>(null);
50
+ const [isWheelZooming, setIsWheelZooming] = useState(false);
51
+
52
+ const wheelTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
53
+ const overlayRef = useRef<HTMLDivElement>(null);
54
+ const viewportRef = useRef<HTMLDivElement>(null);
55
+ const contentRef = useRef<HTMLDivElement>(null);
56
+ const renderedScaleRef = useRef(scale);
57
+
58
+ useModalScrollLock(isOpen);
59
+
60
+ // Keep track of the actually rendered scale for accurate measurements
61
+ useLayoutEffect(() => {
62
+ renderedScaleRef.current = scale;
63
+ }, [scale]);
64
+
65
+ const minScale = baseScale * MIN_SCALE_FACTOR;
66
+ const maxScale = baseScale * MAX_SCALE_FACTOR;
67
+
68
+ const clampScale = useCallback(
69
+ (value: number) => Math.min(maxScale, Math.max(minScale, value)),
70
+ [minScale, maxScale],
71
+ );
72
+
73
+ const calculateFitScale = useCallback(() => {
74
+ if (!viewportRef.current || !contentRef.current) return 1;
75
+
76
+ const viewport = viewportRef.current.getBoundingClientRect();
77
+ const svg = contentRef.current.querySelector('svg');
78
+ if (!svg) return 1;
79
+
80
+ const svgRect = svg.getBoundingClientRect();
81
+ if (!svgRect.width || !svgRect.height) return 1;
82
+
83
+ // getBoundingClientRect returns transformed size, so compensate for current scale
84
+ const currentScale = renderedScaleRef.current || 1;
85
+ const naturalWidth = svgRect.width / currentScale;
86
+ const naturalHeight = svgRect.height / currentScale;
87
+
88
+ const availableWidth = viewport.width - VIEWPORT_PADDING * 2;
89
+ const availableHeight = viewport.height - VIEWPORT_PADDING * 2;
90
+
91
+ return (
92
+ Math.min(availableWidth / naturalWidth, availableHeight / naturalHeight) * FIT_SCALE_FACTOR
93
+ );
94
+ }, []);
95
+
96
+ const resetView = useCallback(() => {
97
+ setScale(baseScale);
98
+ setPosition({ x: 0, y: 0 });
99
+ }, [baseScale]);
100
+
101
+ const zoomIn = useCallback(() => {
102
+ setScale((s) => clampScale(s + baseScale * ZOOM_STEP));
103
+ }, [baseScale, clampScale]);
104
+
105
+ const zoomOut = useCallback(() => {
106
+ setScale((s) => clampScale(s - baseScale * ZOOM_STEP));
107
+ }, [baseScale, clampScale]);
108
+
109
+ const handleKeyDown = useCallback(
110
+ (e: React.KeyboardEvent) => {
111
+ switch (e.key) {
112
+ case 'Escape':
113
+ onClose();
114
+ break;
115
+ case '+':
116
+ case '=':
117
+ zoomIn();
118
+ break;
119
+ case '-':
120
+ zoomOut();
121
+ break;
122
+ case '0':
123
+ resetView();
124
+ break;
125
+ }
126
+ },
127
+ [onClose, zoomIn, zoomOut, resetView],
128
+ );
129
+
130
+ const handleWheel = useCallback(
131
+ (e: WheelEvent) => {
132
+ e.preventDefault();
133
+ e.stopPropagation();
134
+
135
+ setIsWheelZooming(true);
136
+ if (wheelTimeoutRef.current) clearTimeout(wheelTimeoutRef.current);
137
+ wheelTimeoutRef.current = setTimeout(() => setIsWheelZooming(false), 150);
138
+
139
+ const delta = -e.deltaY * WHEEL_SENSITIVITY;
140
+ setScale((s) => clampScale(s + s * delta));
141
+ },
142
+ [clampScale],
143
+ );
144
+
145
+ const handleMouseDown = useCallback(
146
+ (e: MouseEvent) => {
147
+ if (e.button !== 0) return;
148
+ e.preventDefault();
149
+ setIsDragging(true);
150
+ setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y });
151
+ },
152
+ [position],
153
+ );
154
+
155
+ const handleMouseMove = useCallback(
156
+ (e: MouseEvent) => {
157
+ if (!isDragging) return;
158
+ setPosition({ x: e.clientX - dragStart.x, y: e.clientY - dragStart.y });
159
+ },
160
+ [isDragging, dragStart],
161
+ );
162
+
163
+ const handleMouseUp = useCallback(() => setIsDragging(false), []);
164
+
165
+ const getTouchDistance = (touches: React.TouchList): number => {
166
+ if (touches.length !== 2) return 0;
167
+ const dx = touches[0].clientX - touches[1].clientX;
168
+ const dy = touches[0].clientY - touches[1].clientY;
169
+ return Math.hypot(dx, dy);
170
+ };
171
+
172
+ const handleTouchStart = useCallback(
173
+ (e: ReactTouchEvent) => {
174
+ if (e.touches.length === 2) {
175
+ setPinchState({ distance: getTouchDistance(e.touches), scale });
176
+ } else if (e.touches.length === 1) {
177
+ setIsDragging(true);
178
+ setDragStart({
179
+ x: e.touches[0].clientX - position.x,
180
+ y: e.touches[0].clientY - position.y,
181
+ });
182
+ }
183
+ },
184
+ [position, scale],
185
+ );
186
+
187
+ const handleTouchMove = useCallback(
188
+ (e: ReactTouchEvent) => {
189
+ e.preventDefault();
190
+ if (e.touches.length === 2 && pinchState) {
191
+ const distance = getTouchDistance(e.touches);
192
+ setScale(clampScale(pinchState.scale * (distance / pinchState.distance)));
193
+ } else if (e.touches.length === 1 && isDragging) {
194
+ setPosition({
195
+ x: e.touches[0].clientX - dragStart.x,
196
+ y: e.touches[0].clientY - dragStart.y,
197
+ });
198
+ }
199
+ },
200
+ [pinchState, isDragging, dragStart, clampScale],
201
+ );
202
+
203
+ const handleTouchEnd = useCallback(() => {
204
+ setIsDragging(false);
205
+ setPinchState(null);
206
+ }, []);
207
+
208
+ useEffect(() => {
209
+ if (!isOpen) return;
210
+
211
+ setPosition({ x: 0, y: 0 });
212
+ overlayRef.current?.focus();
213
+
214
+ // Wait for DOM to be ready before measuring
215
+ requestAnimationFrame(() => {
216
+ const fitScale = calculateFitScale();
217
+ setBaseScale(fitScale);
218
+ setScale(fitScale);
219
+ });
220
+ }, [isOpen, calculateFitScale]);
221
+
222
+ if (!isOpen) return null;
223
+
224
+ const zoomPercentage = baseScale > 0 ? Math.round((scale / baseScale) * 100) : 100;
225
+ const isAnimating = !isDragging && !isWheelZooming && !pinchState;
226
+
227
+ return (
228
+ <Overlay
229
+ ref={overlayRef}
230
+ onClick={onClose}
231
+ onKeyDown={handleKeyDown}
232
+ tabIndex={0}
233
+ aria-modal="true"
234
+ role="dialog"
235
+ aria-label={labels.dialogLabel || 'SVG viewer'}
236
+ >
237
+ <Viewport
238
+ ref={viewportRef}
239
+ onClick={(e) => e.stopPropagation()}
240
+ onWheel={handleWheel}
241
+ onMouseDown={handleMouseDown}
242
+ onMouseMove={handleMouseMove}
243
+ onMouseUp={handleMouseUp}
244
+ onMouseLeave={handleMouseUp}
245
+ onTouchStart={handleTouchStart}
246
+ onTouchMove={handleTouchMove}
247
+ onTouchEnd={handleTouchEnd}
248
+ $isDragging={isDragging}
249
+ >
250
+ <Content
251
+ ref={contentRef}
252
+ $isAnimating={isAnimating}
253
+ style={{
254
+ transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px)) scale(${scale})`,
255
+ }}
256
+ >
257
+ {children}
258
+ </Content>
259
+ <Controls>
260
+ <ControlGroup>
261
+ <Tooltip tip={labels.zoomOut || 'Zoom out'} placement="top">
262
+ <ControlButton
263
+ variant="text"
264
+ size="small"
265
+ icon={<SubtractIcon />}
266
+ onClick={zoomOut}
267
+ disabled={scale <= minScale}
268
+ />
269
+ </Tooltip>
270
+ <ZoomLabel>{zoomPercentage}%</ZoomLabel>
271
+ <Tooltip tip={labels.zoomIn || 'Zoom in'} placement="top">
272
+ <ControlButton
273
+ variant="text"
274
+ size="small"
275
+ icon={<AddIcon />}
276
+ onClick={zoomIn}
277
+ disabled={scale >= maxScale}
278
+ />
279
+ </Tooltip>
280
+ <Divider />
281
+ <Tooltip tip={labels.fitToView || 'Fit to view'} placement="top">
282
+ <ControlButton
283
+ variant="text"
284
+ size="small"
285
+ icon={<FitToViewIcon />}
286
+ onClick={resetView}
287
+ />
288
+ </Tooltip>
289
+ <Tooltip tip={labels.close || 'Close'} placement="top">
290
+ <ControlButton variant="text" size="small" icon={<CloseIcon />} onClick={onClose} />
291
+ </Tooltip>
292
+ </ControlGroup>
293
+ </Controls>
294
+ </Viewport>
295
+ </Overlay>
296
+ );
297
+ }
298
+
299
+ const scaleIn = keyframes`
300
+ from {
301
+ transform: scale(0.9);
302
+ }
303
+ to {
304
+ transform: scale(1);
305
+ }
306
+ `;
307
+
308
+ const slideUp = keyframes`
309
+ from {
310
+ opacity: 0;
311
+ transform: translateX(-50%) translateY(10px);
312
+ }
313
+ to {
314
+ opacity: 1;
315
+ transform: translateX(-50%) translateY(0);
316
+ }
317
+ `;
318
+
319
+ const Overlay = styled.div`
320
+ position: fixed;
321
+ inset: 0;
322
+ background-color: var(--svg-viewer-overlay-bg-color);
323
+ backdrop-filter: blur(var(--spacing-unit));
324
+ z-index: var(--z-index-overlay, 1000);
325
+ display: flex;
326
+ align-items: center;
327
+ justify-content: center;
328
+ padding: var(--spacing-xxl);
329
+
330
+ &:focus {
331
+ outline: none;
332
+ }
333
+
334
+ @media (max-width: 768px) {
335
+ padding: var(--spacing-md);
336
+ }
337
+ `;
338
+
339
+ const Viewport = styled.div<{ $isDragging: boolean }>`
340
+ position: relative;
341
+ width: 100%;
342
+ height: 100%;
343
+ background-color: var(--svg-viewer-bg-color);
344
+ border-radius: var(--svg-viewer-border-radius);
345
+ overflow: hidden;
346
+ cursor: ${({ $isDragging }) => ($isDragging ? 'grabbing' : 'grab')};
347
+ touch-action: none;
348
+ box-shadow: var(--svg-viewer-box-shadow);
349
+ animation: ${scaleIn} 0.25s ease-in-out forwards;
350
+ `;
351
+
352
+ const Content = styled.div<{ $isAnimating: boolean }>`
353
+ position: absolute;
354
+ top: 50%;
355
+ left: 50%;
356
+ transform-origin: center center;
357
+ user-select: none;
358
+ pointer-events: none;
359
+ transition: ${({ $isAnimating }) => ($isAnimating ? 'transform 0.25s ease-in-out' : 'none')};
360
+
361
+ svg {
362
+ display: block;
363
+ max-width: none !important;
364
+ }
365
+ `;
366
+
367
+ const Controls = styled.div`
368
+ position: absolute;
369
+ bottom: var(--spacing-sm);
370
+ left: 50%;
371
+ transform: translateX(-50%);
372
+ z-index: 10;
373
+ animation: ${slideUp} 0.3s ease-out 0.1s backwards;
374
+ `;
375
+
376
+ const ControlGroup = styled.div`
377
+ display: flex;
378
+ align-items: center;
379
+ gap: 2px;
380
+ padding: var(--spacing-xxs);
381
+ background: var(--bg-color-raised);
382
+ border: 1px solid var(--border-color-primary);
383
+ border-radius: var(--border-radius-lg);
384
+ box-shadow: var(--bg-raised-shadow);
385
+ `;
386
+
387
+ const ControlButton = styled(Button)`
388
+ --button-icon-size: 16px;
389
+ `;
390
+
391
+ const ZoomLabel = styled.span`
392
+ min-width: 40px;
393
+ font-size: var(--font-size-sm);
394
+ font-weight: var(--font-weight-semibold);
395
+ color: var(--text-color-secondary);
396
+ text-align: center;
397
+ font-variant-numeric: tabular-nums;
398
+ `;
399
+
400
+ const Divider = styled.div`
401
+ width: 1px;
402
+ height: var(--spacing-base);
403
+ background: var(--border-color-primary);
404
+ margin: 0 var(--spacing-xxs);
405
+ `;
@@ -0,0 +1,5 @@
1
+ import { css } from 'styled-components';
2
+
3
+ export const svgViewerDarkMode = css`
4
+ --svg-viewer-bg-color: var(--color-warm-grey-9);
5
+ `;
@@ -0,0 +1,14 @@
1
+ import { css } from 'styled-components';
2
+
3
+ export const svgViewer = css`
4
+ /**
5
+ * @tokens SVG Viewer
6
+ */
7
+
8
+ --svg-viewer-overlay-bg-color: var(--bg-color-modal-overlay); // @presenter Color
9
+ --svg-viewer-bg-color: var(--bg-color); // @presenter Color
10
+ --svg-viewer-border-radius: var(--border-radius-xl); // @presenter BorderRadius
11
+ --svg-viewer-box-shadow: var(--bg-raised-shadow); // @presenter BoxShadow
12
+
13
+ // @tokens End
14
+ `;
@@ -243,7 +243,8 @@ const TagWrapper = styled.div.attrs(({ className, color, size, variant }: TagPro
243
243
  `text-transform: ${textTransform ? `${textTransform}` : 'var(--tag-text-transform)'};`}
244
244
 
245
245
  color: var(--tag-color);
246
- background-color: var(--tag-bg-color);
246
+ background-color: ${({ variant }) =>
247
+ variant === 'filled' ? 'var(--tag-bg-color)' : 'transparent'};
247
248
  ${({ borderless }) =>
248
249
  borderless
249
250
  ? ''
@@ -182,6 +182,12 @@ export const tagDarkMode = css`
182
182
  --tag-bg-color-hover: #3A465F; // @presenter Color
183
183
  }
184
184
 
185
+ .tag-query {
186
+ --tag-color: #68cc97; // @presenter Color
187
+ --tag-bg-color: #1F3D2D; // @presenter Color
188
+ --tag-bg-color-hover: #34654B; // @presenter Color
189
+ }
190
+
185
191
  .tag-put {
186
192
  --tag-color: #e0a663; // @presenter Color
187
193
  --tag-bg-color: #3D2D1B; // @presenter Color
@@ -295,6 +295,12 @@ export const tag = css`
295
295
  --tag-bg-color-hover: #CEDDFD; // @presenter Color
296
296
  }
297
297
 
298
+ .tag-query {
299
+ --tag-color: #25b869; // @presenter Color
300
+ --tag-bg-color: #e5faef; // @presenter Color
301
+ --tag-bg-color-hover: #D4F7E5; // @presenter Color
302
+ }
303
+
298
304
  .tag-put {
299
305
  --tag-color: #f5901d; // @presenter Color
300
306
  --tag-bg-color: #fef1e2; // @presenter Color