@likec4/diagram 1.31.0 → 1.32.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 (264) hide show
  1. package/bundle/{chunk-BBzMXzCg.js → chunk-BvTQaUYl.js} +1675 -1207
  2. package/bundle/custom.js +50 -47
  3. package/bundle/index.js +2482 -2438
  4. package/dist/LikeC4CustomColors.d.ts +2 -7
  5. package/dist/LikeC4CustomColors.js +17 -6
  6. package/dist/LikeC4Diagram.d.ts +3 -2
  7. package/dist/LikeC4Diagram.js +10 -14
  8. package/dist/LikeC4Diagram.props.d.ts +28 -22
  9. package/dist/LikeC4ModelProvider.d.ts +5 -4
  10. package/dist/StaticLikeC4Diagram.d.ts +3 -2
  11. package/dist/StaticLikeC4Diagram.js +2 -2
  12. package/dist/base/BaseXYFlow.js +5 -5
  13. package/dist/base/const.d.ts +1 -1
  14. package/dist/base/const.js +1 -1
  15. package/dist/base/index.d.ts +2 -1
  16. package/dist/base/primitives/compound/CompoundActionButton.js +2 -1
  17. package/dist/base/primitives/compound/CompoundDetailsButton.js +2 -1
  18. package/dist/base/primitives/compound/CompoundTitle.d.ts +1 -1
  19. package/dist/base/primitives/compound/CompoundTitle.js +2 -1
  20. package/dist/base/primitives/edge/EdgeContainer.d.ts +1 -1
  21. package/dist/base/primitives/edge/EdgeLabel.css.js +1 -0
  22. package/dist/base/primitives/edge/EdgeLabel.d.ts +3 -3
  23. package/dist/base/primitives/edge/EdgeLabel.js +6 -4
  24. package/dist/base/primitives/edge/EdgeLabelContainer.d.ts +1 -1
  25. package/dist/base/primitives/edge/EdgeMarkers.d.ts +1 -1
  26. package/dist/base/primitives/edge/EdgePath.d.ts +1 -1
  27. package/dist/base/primitives/element/ElementActionButtons.js +10 -9
  28. package/dist/base/primitives/element/ElementDetailsButton.js +2 -1
  29. package/dist/base/primitives/element/ElementShape.d.ts +1 -1
  30. package/dist/base/primitives/element/ElementTags.d.ts +14 -0
  31. package/dist/base/primitives/element/ElementTags.js +176 -0
  32. package/dist/base/primitives/element/ElementTitle.d.ts +5 -4
  33. package/dist/base/primitives/element/ElementTitle.js +6 -6
  34. package/dist/base/primitives/index.d.ts +1 -0
  35. package/dist/base/types.Base.d.ts +54 -0
  36. package/dist/base/types.Base.js +48 -0
  37. package/dist/base/types.d.ts +2 -52
  38. package/dist/bundle/LikeC4View.d.ts +2 -1
  39. package/dist/bundle/LikeC4View.js +8 -6
  40. package/dist/bundle/LikeC4View.props.d.ts +15 -4
  41. package/dist/bundle/ReactLikeC4.d.ts +4 -7
  42. package/dist/bundle/ReactLikeC4.js +3 -2
  43. package/dist/bundle/index.js +1 -1
  44. package/dist/components/ErrorFallback.d.ts +2 -0
  45. package/dist/components/ErrorFallback.js +29 -0
  46. package/dist/context/DiagramEventHandlers.d.ts +6 -5
  47. package/dist/context/DiagramFeatures.d.ts +2 -2
  48. package/dist/context/DiagramFeatures.js +3 -31
  49. package/dist/context/EnsureMantine.js +1 -1
  50. package/dist/context/IconRenderer.js +1 -4
  51. package/dist/context/RootContainer.js +5 -1
  52. package/dist/context/TagStylesContext.d.ts +7 -0
  53. package/dist/context/TagStylesContext.js +85 -0
  54. package/dist/custom/components.d.ts +1 -1
  55. package/dist/custom/customNodes.d.ts +27 -17
  56. package/dist/custom/hooks.d.ts +1 -1
  57. package/dist/hooks/index.d.ts +1 -1
  58. package/dist/hooks/useDiagram.d.ts +73 -38
  59. package/dist/hooks/useDiagram.js +7 -3
  60. package/dist/hooks/useMantinePortalProps.d.ts +2 -2
  61. package/dist/hooks/useSearchActor.d.ts +2 -0
  62. package/dist/hooks/useSearchActor.js +10 -0
  63. package/dist/hooks/useUpdateEffect.js +3 -0
  64. package/dist/hooks/useXYFlow.d.ts +39 -37
  65. package/dist/hooks/useXYFlow.js +5 -1
  66. package/dist/index.js +1 -1
  67. package/dist/likec4diagram/DiagramUI.js +7 -2
  68. package/dist/likec4diagram/DiagramXYFlow.d.ts +4 -3
  69. package/dist/likec4diagram/DiagramXYFlow.js +104 -107
  70. package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +7 -6
  71. package/dist/likec4diagram/custom/edges/RelationshipEdge.js +8 -0
  72. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +7 -5
  73. package/dist/likec4diagram/custom/index.d.ts +7 -6
  74. package/dist/likec4diagram/custom/nodes/nodes.js +39 -26
  75. package/dist/likec4diagram/custom/nodes/toolbar/_shared.d.ts +3 -3
  76. package/dist/likec4diagram/types.d.ts +5 -5
  77. package/dist/likec4diagram/ui/controls/Controls.js +12 -4
  78. package/dist/likec4diagram/ui/notation/NotationPanel.js +1 -1
  79. package/dist/likec4diagram/useViewToNodesEdges.d.ts +5 -3
  80. package/dist/likec4diagram/useViewToNodesEdges.js +20 -30
  81. package/dist/likec4model/LikeC4ModelContext.d.ts +2 -2
  82. package/dist/likec4model/useLikeC4ElementsTree.js +1 -1
  83. package/dist/likec4model/useLikeC4Model.d.ts +22 -10
  84. package/dist/likec4model/useLikeC4Model.js +11 -7
  85. package/dist/overlays/Overlays.js +4 -27
  86. package/dist/overlays/element-details/ElementDetailsCard.d.ts +1 -1
  87. package/dist/overlays/element-details/ElementDetailsCard.js +19 -12
  88. package/dist/overlays/element-details/TabPanelDeployments.d.ts +1 -1
  89. package/dist/overlays/element-details/TabPanelDeployments.js +1 -1
  90. package/dist/overlays/element-details/TabPanelRelationships.d.ts +1 -1
  91. package/dist/overlays/element-details/TabPanelStructure.d.ts +1 -1
  92. package/dist/overlays/element-details/actor.d.ts +288 -286
  93. package/dist/overlays/overlay/Overlay.css.d.ts +57 -2
  94. package/dist/overlays/overlay/Overlay.css.js +76 -39
  95. package/dist/overlays/overlay/Overlay.d.ts +12 -0
  96. package/dist/overlays/overlay/Overlay.js +36 -25
  97. package/dist/overlays/overlaysActor.d.ts +1 -1
  98. package/dist/overlays/relationship-details/RelationshipDetails.d.ts +3 -2
  99. package/dist/overlays/relationship-details/RelationshipDetails.js +3 -3
  100. package/dist/overlays/relationship-details/_types.d.ts +2 -2
  101. package/dist/overlays/relationship-details/actor.js +7 -7
  102. package/dist/overlays/relationship-details/custom/edgeTypes.d.ts +3 -2
  103. package/dist/overlays/relationship-details/custom/nodeTypes.js +4 -0
  104. package/dist/overlays/relationship-details/hooks.d.ts +10 -9
  105. package/dist/overlays/relationship-details/layout-to-xyflow.js +1 -0
  106. package/dist/overlays/relationship-details/layout.js +3 -1
  107. package/dist/overlays/relationships-browser/RelationshipsBrowser.d.ts +3 -2
  108. package/dist/overlays/relationships-browser/SelectElement.js +1 -1
  109. package/dist/overlays/relationships-browser/_types.d.ts +2 -2
  110. package/dist/overlays/relationships-browser/actor.d.ts +1 -1
  111. package/dist/overlays/relationships-browser/actor.js +7 -7
  112. package/dist/overlays/relationships-browser/custom/edgeTypes.d.ts +3 -2
  113. package/dist/overlays/relationships-browser/custom/nodeTypes.d.ts +8 -5
  114. package/dist/overlays/relationships-browser/custom/nodeTypes.js +4 -0
  115. package/dist/overlays/relationships-browser/layout.d.ts +2 -2
  116. package/dist/overlays/relationships-browser/layout.js +10 -6
  117. package/dist/overlays/relationships-browser/useViewToNodesEdges.js +4 -3
  118. package/dist/search/Search.d.ts +5 -0
  119. package/dist/search/Search.js +192 -0
  120. package/dist/{likec4diagram/ui/search → search/components}/ElementsColumn.css.js +0 -1
  121. package/dist/search/components/ElementsColumn.d.ts +2 -0
  122. package/dist/{likec4diagram/ui/search → search/components}/ElementsColumn.js +21 -19
  123. package/dist/search/components/PickView.d.ts +4 -0
  124. package/dist/search/components/PickView.js +135 -0
  125. package/dist/search/components/SearchByTags.d.ts +1 -0
  126. package/dist/search/components/SearchByTags.js +116 -0
  127. package/dist/search/components/SearchInput.d.ts +2 -0
  128. package/dist/{likec4diagram/ui/search → search/components}/SearchInput.js +53 -34
  129. package/dist/{likec4diagram/ui/search → search/components}/ViewsColum.d.ts +3 -2
  130. package/dist/{likec4diagram/ui/search → search/components}/ViewsColum.js +14 -13
  131. package/dist/{likec4diagram/ui/search → search/components}/_shared.css.js +26 -35
  132. package/dist/{likec4diagram/ui/search/LikeC4Search.css.d.ts → search/components/styles.css.d.ts} +0 -2
  133. package/dist/search/components/styles.css.js +60 -0
  134. package/dist/{likec4diagram/ui/search → search/components}/utils.d.ts +1 -0
  135. package/dist/{likec4diagram/ui/search → search/components}/utils.js +7 -1
  136. package/dist/search/hooks.d.ts +16 -0
  137. package/dist/search/hooks.js +35 -0
  138. package/dist/search/searchActor.d.ts +90 -0
  139. package/dist/search/searchActor.js +75 -0
  140. package/dist/state/DiagramActorProvider.d.ts +9 -7
  141. package/dist/state/DiagramActorProvider.js +24 -18
  142. package/dist/state/assign.d.ts +0 -1
  143. package/dist/state/assign.js +9 -19
  144. package/dist/state/diagram-machine.d.ts +430 -176
  145. package/dist/state/diagram-machine.js +119 -54
  146. package/dist/state/syncManualLayoutActor.d.ts +2 -2
  147. package/dist/state/types.d.ts +2 -0
  148. package/dist/state/utils.d.ts +2 -0
  149. package/dist/state/utils.js +3 -0
  150. package/dist/styles-min.css +1 -1
  151. package/dist/styles-xyflow.css +1 -1
  152. package/dist/styles.css +1 -1
  153. package/dist/styles.css2.js +1 -1
  154. package/package.json +18 -18
  155. package/panda.buildinfo.json +171 -148
  156. package/src/LikeC4CustomColors.tsx +21 -6
  157. package/src/LikeC4Diagram.props.ts +35 -30
  158. package/src/LikeC4Diagram.tsx +19 -20
  159. package/src/LikeC4ModelProvider.tsx +6 -5
  160. package/src/StaticLikeC4Diagram.tsx +8 -6
  161. package/src/base/const.ts +1 -1
  162. package/src/base/index.ts +2 -1
  163. package/src/base/primitives/compound/CompoundActionButton.tsx +2 -1
  164. package/src/base/primitives/compound/CompoundDetailsButton.tsx +2 -1
  165. package/src/base/primitives/compound/CompoundTitle.tsx +3 -2
  166. package/src/base/primitives/edge/EdgeContainer.tsx +2 -1
  167. package/src/base/primitives/edge/EdgeLabel.css.ts +1 -0
  168. package/src/base/primitives/edge/EdgeLabel.tsx +20 -15
  169. package/src/base/primitives/edge/EdgeLabelContainer.tsx +1 -1
  170. package/src/base/primitives/edge/EdgeMarkers.tsx +2 -1
  171. package/src/base/primitives/edge/EdgePath.tsx +1 -1
  172. package/src/base/primitives/element/ElementActionButtons.tsx +11 -10
  173. package/src/base/primitives/element/ElementDetailsButton.tsx +2 -1
  174. package/src/base/primitives/element/ElementShape.tsx +2 -1
  175. package/src/base/primitives/element/ElementTags.tsx +182 -0
  176. package/src/base/primitives/element/ElementTitle.tsx +21 -15
  177. package/src/base/primitives/index.ts +1 -0
  178. package/src/base/types.Base.ts +104 -0
  179. package/src/base/types.ts +2 -99
  180. package/src/bundle/LikeC4View.props.ts +17 -4
  181. package/src/bundle/LikeC4View.tsx +17 -19
  182. package/src/bundle/ReactLikeC4.tsx +14 -26
  183. package/src/components/ErrorFallback.tsx +30 -0
  184. package/src/context/DiagramEventHandlers.tsx +5 -4
  185. package/src/context/DiagramFeatures.tsx +3 -22
  186. package/src/context/EnsureMantine.tsx +1 -1
  187. package/src/context/IconRenderer.tsx +1 -4
  188. package/src/context/RootContainer.tsx +9 -3
  189. package/src/context/TagStylesContext.tsx +96 -0
  190. package/src/custom/components.ts +2 -0
  191. package/src/custom/customNodes.tsx +24 -14
  192. package/src/custom/hooks.ts +1 -0
  193. package/src/hooks/index.ts +1 -1
  194. package/src/hooks/useCurrentViewId.ts +1 -4
  195. package/src/hooks/useDiagram.ts +104 -12
  196. package/src/hooks/useMantinePortalProps.ts +10 -1
  197. package/src/hooks/useSearchActor.ts +11 -0
  198. package/src/hooks/useUpdateEffect.ts +7 -4
  199. package/src/hooks/useXYFlow.ts +5 -0
  200. package/src/likec4diagram/DiagramUI.tsx +5 -0
  201. package/src/likec4diagram/DiagramXYFlow.tsx +115 -118
  202. package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +9 -0
  203. package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +10 -9
  204. package/src/likec4diagram/custom/nodes/nodes.tsx +45 -43
  205. package/src/likec4diagram/custom/nodes/toolbar/_shared.tsx +11 -3
  206. package/src/likec4diagram/types.ts +5 -3
  207. package/src/likec4diagram/ui/controls/Controls.tsx +11 -4
  208. package/src/likec4diagram/ui/notation/NotationPanel.tsx +2 -2
  209. package/src/likec4diagram/useViewToNodesEdges.ts +34 -36
  210. package/src/likec4model/LikeC4ModelContext.ts +2 -2
  211. package/src/likec4model/useLikeC4ElementsTree.ts +1 -1
  212. package/src/likec4model/useLikeC4Model.ts +18 -16
  213. package/src/overlays/Overlays.tsx +5 -32
  214. package/src/overlays/element-details/ElementDetailsCard.tsx +25 -18
  215. package/src/overlays/element-details/TabPanelDeployments.tsx +3 -2
  216. package/src/overlays/element-details/TabPanelRelationships.tsx +2 -1
  217. package/src/overlays/element-details/TabPanelStructure.tsx +1 -1
  218. package/src/overlays/element-details/actor.ts +2 -2
  219. package/src/overlays/overlay/Overlay.css.ts +75 -38
  220. package/src/overlays/overlay/Overlay.tsx +43 -26
  221. package/src/overlays/overlaysActor.ts +1 -1
  222. package/src/overlays/relationship-details/RelationshipDetails.tsx +4 -4
  223. package/src/overlays/relationship-details/_types.ts +2 -1
  224. package/src/overlays/relationship-details/custom/nodeTypes.tsx +4 -0
  225. package/src/overlays/relationship-details/layout-to-xyflow.ts +1 -0
  226. package/src/overlays/relationship-details/layout.ts +3 -1
  227. package/src/overlays/relationships-browser/SelectElement.tsx +1 -1
  228. package/src/overlays/relationships-browser/_types.ts +2 -1
  229. package/src/overlays/relationships-browser/custom/nodeTypes.tsx +4 -0
  230. package/src/overlays/relationships-browser/layout.ts +12 -7
  231. package/src/overlays/relationships-browser/useViewToNodesEdges.ts +4 -4
  232. package/src/search/Search.tsx +237 -0
  233. package/src/{likec4diagram/ui/search → search/components}/ElementsColumn.css.ts +0 -29
  234. package/src/{likec4diagram/ui/search → search/components}/ElementsColumn.tsx +24 -22
  235. package/src/search/components/PickView.tsx +140 -0
  236. package/src/search/components/SearchByTags.tsx +109 -0
  237. package/src/{likec4diagram/ui/search → search/components}/SearchInput.tsx +63 -36
  238. package/src/{likec4diagram/ui/search → search/components}/ViewsColum.tsx +17 -18
  239. package/src/{likec4diagram/ui/search → search/components}/_shared.css.ts +26 -37
  240. package/src/{likec4diagram/ui/search/LikeC4Search.css.ts → search/components/styles.css.ts} +9 -36
  241. package/src/{likec4diagram/ui/search → search/components}/utils.ts +7 -0
  242. package/src/search/hooks.ts +41 -0
  243. package/src/search/searchActor.ts +99 -0
  244. package/src/state/DiagramActorProvider.tsx +36 -25
  245. package/src/state/assign.ts +10 -10
  246. package/src/state/diagram-machine.ts +115 -52
  247. package/src/state/syncManualLayoutActor.ts +1 -1
  248. package/src/state/types.ts +2 -0
  249. package/src/state/utils.ts +4 -0
  250. package/dist/base/types.js +0 -54
  251. package/dist/likec4diagram/ui/search/ElementsColumn.d.ts +0 -1
  252. package/dist/likec4diagram/ui/search/LikeC4Search.css.js +0 -87
  253. package/dist/likec4diagram/ui/search/LikeC4Search.d.ts +0 -2
  254. package/dist/likec4diagram/ui/search/LikeC4Search.js +0 -267
  255. package/dist/likec4diagram/ui/search/SearchInput.d.ts +0 -1
  256. package/dist/likec4diagram/ui/search/state.d.ts +0 -19
  257. package/dist/likec4diagram/ui/search/state.js +0 -63
  258. package/src/likec4diagram/ui/search/LikeC4Search.tsx +0 -301
  259. package/src/likec4diagram/ui/search/state.ts +0 -78
  260. /package/dist/{likec4diagram/ui/search → search/components}/ElementsColumn.css.d.ts +0 -0
  261. /package/dist/{likec4diagram/ui/search → search/components}/ViewsColumn.css.d.ts +0 -0
  262. /package/dist/{likec4diagram/ui/search → search/components}/ViewsColumn.css.js +0 -0
  263. /package/dist/{likec4diagram/ui/search → search/components}/_shared.css.d.ts +0 -0
  264. /package/src/{likec4diagram/ui/search → search/components}/ViewsColumn.css.ts +0 -0
@@ -1,4 +1,3 @@
1
- import { compareNatural } from '@likec4/core'
2
1
  import {
3
2
  Combobox,
4
3
  ComboboxDropdown,
@@ -12,15 +11,15 @@ import {
12
11
  Text,
13
12
  useCombobox,
14
13
  } from '@mantine/core'
15
- import { useDebouncedValue, useFocusWithin, useIsFirstRender, useWindowEvent } from '@mantine/hooks'
14
+ import { useFocusWithin, useWindowEvent } from '@mantine/hooks'
16
15
  import { usePreviousDistinct } from '@react-hookz/web'
17
16
  import { IconSearch } from '@tabler/icons-react'
18
- import { type ReactNode } from 'react'
19
- import { isString, keys, only } from 'remeda'
20
- import { useLikeC4Model } from '../../../likec4model/useLikeC4Model'
21
- import * as css from './LikeC4Search.css'
22
- import { setSearch, useIsPickViewActive, useSearch } from './state'
23
- import { moveFocusToSearchInput, stopAndPrevent } from './utils'
17
+ import { type ReactNode, memo } from 'react'
18
+ import { keys, only } from 'remeda'
19
+ import { useLikeC4Model } from '../../likec4model/useLikeC4Model'
20
+ import { useSearch, useSearchActor } from '../hooks'
21
+ import * as css from './styles.css'
22
+ import { focusToFirstFoundElement, moveFocusToSearchInput, stopAndPrevent } from './utils'
24
23
 
25
24
  function startingWithKind(search: string) {
26
25
  return search.match(/^(k|ki|kin|kind|kind:)$/) != null
@@ -28,25 +27,34 @@ function startingWithKind(search: string) {
28
27
 
29
28
  const SEARCH_PREFIXES = ['#', 'kind:']
30
29
 
31
- export function LikeC4SearchInput() {
32
- const isPickViewActive = useIsPickViewActive()
33
- const likec4model = useLikeC4Model(true)
34
- const combobox = useCombobox({
35
- scrollBehavior: 'smooth',
36
- })
30
+ export const LikeC4SearchInput = memo(() => {
31
+ const { close, searchActorRef } = useSearchActor()
32
+ const likec4model = useLikeC4Model()
37
33
  const { ref, focused } = useFocusWithin<HTMLInputElement>()
38
- const search = useSearch()
34
+ const [search, setSearch] = useSearch()
39
35
  const previous = usePreviousDistinct(search)
40
- const isFirstRender = useIsFirstRender()
41
36
 
42
- const [isEmptyForSomeTime] = useDebouncedValue(search === '' && !isFirstRender, isString(previous) ? 500 : 2000)
37
+ // const [isEmptyForSomeTime, cancel] = useDebouncedValue(
38
+ // focused ? search : 'rstrs',
39
+ // 2000,
40
+ // )
41
+ // // useF
42
+ // // const isEmptyForSomeTime = debouncedSearch === ''
43
+ // useEffect(() => {
44
+ // // cancel()
45
+ // }, [])
46
+
47
+ const combobox = useCombobox({
48
+ scrollBehavior: 'smooth',
49
+ loop: false,
50
+ })
43
51
 
44
52
  useWindowEvent(
45
53
  'keydown',
46
54
  (event) => {
47
55
  try {
48
56
  if (
49
- !focused && !isPickViewActive && (
57
+ !focused && (
50
58
  event.key === 'Backspace' ||
51
59
  event.key.startsWith('Arrow') ||
52
60
  event.key.match(/^\p{L}$/u)
@@ -64,20 +72,18 @@ export function LikeC4SearchInput() {
64
72
  let isExactMatch = false
65
73
 
66
74
  switch (true) {
67
- case search === '' && (isEmptyForSomeTime || SEARCH_PREFIXES.includes(previous ?? '')): {
68
- options = SEARCH_PREFIXES.map((prefix) => (
69
- <ComboboxOption value={prefix} key={prefix}>
70
- <Text component="span" opacity={.5} mr={4} fz={'sm'}>Search by</Text>
71
- {prefix}
72
- </ComboboxOption>
73
- ))
74
- break
75
- }
75
+ // case search === '' && isEmptyForSomeTime === '': {
76
+ // options = SEARCH_PREFIXES.map((prefix) => (
77
+ // <ComboboxOption value={prefix} key={prefix}>
78
+ // <Text component="span" opacity={.5} mr={4} fz={'sm'}>Search by</Text>
79
+ // {prefix}
80
+ // </ComboboxOption>
81
+ // ))
82
+ // break
83
+ // }
76
84
  case search.startsWith('#'): {
77
85
  const searchTag = search.toLocaleLowerCase().slice(1)
78
- const alloptions = likec4model.allTags().filter((tag) => tag.toLocaleLowerCase().includes(searchTag)).sort(
79
- compareNatural,
80
- )
86
+ const alloptions = likec4model.tags.filter((tag) => tag.toLocaleLowerCase().includes(searchTag))
81
87
  isExactMatch = only(alloptions)?.toLocaleLowerCase() === searchTag
82
88
  if (alloptions.length === 0) {
83
89
  options = [
@@ -98,7 +104,7 @@ export function LikeC4SearchInput() {
98
104
  case search.startsWith('kind:'):
99
105
  case startingWithKind(search): {
100
106
  const term = search.length > 5 ? search.slice(5).toLocaleLowerCase() : ''
101
- let alloptions = keys(likec4model.$model.specification.elements)
107
+ let alloptions = keys(likec4model.specification.elements)
102
108
  if (term) {
103
109
  alloptions = alloptions.filter((kind) => kind.toLocaleLowerCase().includes(term))
104
110
  isExactMatch = only(alloptions)?.toLocaleLowerCase() === term
@@ -130,8 +136,8 @@ export function LikeC4SearchInput() {
130
136
  combobox.closeDropdown()
131
137
  // Let react to display filtered elements
132
138
  setTimeout(() => {
133
- document.querySelector<HTMLButtonElement>(`[data-likec4-search] .${css.focusable}`)?.focus()
134
- }, 50)
139
+ focusToFirstFoundElement()
140
+ }, 350)
135
141
  }
136
142
  }}
137
143
  width={'max-content'}
@@ -149,13 +155,27 @@ export function LikeC4SearchInput() {
149
155
  ref={ref}
150
156
  id="likec4searchinput"
151
157
  placeholder="Search by title, description or start with # or kind:"
158
+ autoFocus
152
159
  tabIndex={0}
153
160
  classNames={{
154
161
  input: css.input,
155
162
  }}
156
- size="xl"
163
+ size="lg"
157
164
  value={search}
158
165
  leftSection={<IconSearch style={{ width: rem(20) }} stroke={2} />}
166
+ rightSection={
167
+ <Input.ClearButton
168
+ onClick={(e) => {
169
+ e.stopPropagation()
170
+ const openedWithSearch = searchActorRef.getSnapshot().context.openedWithSearch
171
+ if (search === '' || search === openedWithSearch) {
172
+ close()
173
+ } else {
174
+ setSearch('')
175
+ }
176
+ }} />
177
+ }
178
+ rightSectionPointerEvents="auto"
159
179
  onChange={(event) => {
160
180
  setSearch(event.currentTarget.value)
161
181
  combobox.openDropdown()
@@ -207,6 +227,13 @@ export function LikeC4SearchInput() {
207
227
  combobox.closeDropdown()
208
228
  return
209
229
  }
230
+ if (
231
+ e.key === 'ArrowUp' && combobox.dropdownOpened && search === '' && combobox.getSelectedOptionIndex() === 0
232
+ ) {
233
+ combobox.closeDropdown()
234
+ stopAndPrevent(e)
235
+ return
236
+ }
210
237
  if (
211
238
  e.key === 'ArrowDown' && (
212
239
  !combobox.dropdownOpened ||
@@ -217,7 +244,7 @@ export function LikeC4SearchInput() {
217
244
  ) {
218
245
  combobox.closeDropdown()
219
246
  stopAndPrevent(e)
220
- document.querySelector<HTMLButtonElement>(`[data-likec4-search] .${css.focusable}`)?.focus()
247
+ focusToFirstFoundElement()
221
248
  return
222
249
  }
223
250
  }} />
@@ -232,4 +259,4 @@ export function LikeC4SearchInput() {
232
259
  </ComboboxDropdown>
233
260
  </Combobox>
234
261
  )
235
- }
262
+ })
@@ -1,8 +1,4 @@
1
- import {
2
- type LikeC4Model,
3
- type Tag,
4
- isDeploymentView,
5
- } from '@likec4/core'
1
+ import type { LikeC4Model } from '@likec4/core/model'
6
2
  import { cx } from '@likec4/styles/css'
7
3
  import { Box } from '@likec4/styles/jsx'
8
4
  import {
@@ -19,11 +15,13 @@ import {
19
15
  } from '@mantine/core'
20
16
  import { IconStack2, IconZoomScan } from '@tabler/icons-react'
21
17
  import * as m from 'motion/react-m'
18
+ import { memo } from 'react'
22
19
  import { first } from 'remeda'
23
- import { useCurrentViewId } from '../../../hooks/useCurrentViewId'
24
- import { useLikeC4Model } from '../../../likec4model/useLikeC4Model'
20
+ import { useCurrentViewId } from '../../hooks/useCurrentViewId'
21
+ import { useDiagram } from '../../hooks/useDiagram'
22
+ import { useLikeC4Model } from '../../likec4model/useLikeC4Model'
23
+ import { useNormalizedSearch } from '../hooks'
25
24
  import { buttonsva } from './_shared.css'
26
- import { useCloseSearchAndNavigateTo, useNormalizedSearch } from './state'
27
25
  import { centerY, moveFocusToSearchInput } from './utils'
28
26
  import * as styles from './ViewsColumn.css'
29
27
 
@@ -33,16 +31,16 @@ export const NothingFound = () => (
33
31
  </Box>
34
32
  )
35
33
 
36
- export function ViewsColumn() {
37
- const search = useNormalizedSearch()
38
- let views = [...useLikeC4Model(true).views()]
34
+ export const ViewsColumn = memo(() => {
35
+ let views = [...useLikeC4Model().views()]
36
+ let search = useNormalizedSearch()
39
37
  if (search) {
40
38
  if (search.startsWith('kind:')) {
41
39
  views = []
42
40
  } else {
43
41
  views = views.filter(view => {
44
42
  if (search.startsWith('#')) {
45
- return view.tags.some((tag: Tag) => tag.toLocaleLowerCase().includes(search.slice(1)))
43
+ return view.tags.some((tag) => tag.toLocaleLowerCase().includes(search.slice(1)))
46
44
  }
47
45
  return (view.title ?? '' + view.$view.description ?? '').toLocaleLowerCase().includes(search)
48
46
  })
@@ -58,7 +56,7 @@ export function ViewsColumn() {
58
56
  if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
59
57
  const maxY = (e.target as HTMLElement).getBoundingClientRect().y
60
58
  const elementButtons = [...document.querySelectorAll<HTMLButtonElement>(
61
- `[data-likec4-search-elements] .likec4-element-button`,
59
+ `[data-likec4-search-elements] .likec4-focusable`,
62
60
  )]
63
61
  let elementButton = elementButtons.length > 1
64
62
  ? elementButtons.find((el, i, all) => centerY(el) > maxY || i === all.length - 1)
@@ -95,7 +93,7 @@ export function ViewsColumn() {
95
93
  ))}
96
94
  </Stack>
97
95
  )
98
- }
96
+ })
99
97
 
100
98
  const btn = buttonsva()
101
99
 
@@ -109,7 +107,8 @@ export function ViewButton(
109
107
  & UnstyledButtonProps
110
108
  & ElementProps<'button'>,
111
109
  ) {
112
- const navigateTo = useCloseSearchAndNavigateTo()
110
+ const diagram = useDiagram()
111
+ // const navigateTo = useCloseSearchAndNavigateTo()
113
112
  const currentViewId = useCurrentViewId()
114
113
  const isCurrentView = view.id === currentViewId
115
114
  return (
@@ -120,7 +119,7 @@ export function ViewButton(
120
119
  {...isCurrentView && { 'data-disabled': true }}
121
120
  onClick={(e) => {
122
121
  e.stopPropagation()
123
- navigateTo(view.id)
122
+ diagram.navigateTo(view.id)
124
123
  }}
125
124
  onKeyDown={createScopedKeydownHandler({
126
125
  siblingSelector: '[data-likec4-view]',
@@ -131,12 +130,12 @@ export function ViewButton(
131
130
  onKeyDown: (e) => {
132
131
  if (e.nativeEvent.code === 'Space') {
133
132
  e.stopPropagation()
134
- navigateTo(view.id)
133
+ diagram.navigateTo(view.id)
135
134
  }
136
135
  },
137
136
  })}>
138
137
  <ThemeIcon variant="transparent" className={btn.icon!}>
139
- {isDeploymentView(view)
138
+ {view.isDeploymentView()
140
139
  ? <IconStack2 stroke={1.8} />
141
140
  : <IconZoomScan stroke={1.8} />}
142
141
  </ThemeIcon>
@@ -1,5 +1,4 @@
1
1
  import { css, sva } from '@likec4/styles/css'
2
- import type { ColorToken } from '@likec4/styles/tokens'
3
2
 
4
3
  // export const titleColor = '--title-color'
5
4
  // export const descriptionColor = '---description-color'
@@ -13,21 +12,6 @@ const buttonFocused = css.raw({
13
12
 
14
13
  const _treenodefocus = '.mantine-Tree-node:focus > .mantine-Tree-label &'
15
14
 
16
- function colors(color: ColorToken, hover: ColorToken) {
17
- return {
18
- color,
19
- _groupHover: {
20
- color: hover,
21
- },
22
- _groupFocus: {
23
- color: hover,
24
- },
25
- [_treenodefocus]: {
26
- color: hover,
27
- },
28
- }
29
- }
30
-
31
15
  const button = css.raw({
32
16
  display: 'flex',
33
17
  width: '100%',
@@ -35,7 +19,7 @@ const button = css.raw({
35
19
  rounded: 'sm',
36
20
  padding: `12px 8px 12px 14px`,
37
21
  minHeight: '60px',
38
- gap: '8',
22
+ gap: 8,
39
23
  // alignItems: 'flex-start',
40
24
  // transition: `all 50ms ${easings.inOut}`,
41
25
  border: `1px solid`,
@@ -76,9 +60,14 @@ const iconSize = {
76
60
  }
77
61
 
78
62
  const icon = css.raw({
79
- ...colors('mantine.colors.dimmed', 'mantine.colors.primary[0]'),
80
- _light: {
81
- ...colors('mantine.colors.gray[6]', 'mantine.colors.primary[3]'),
63
+ color: {
64
+ base: 'mantine.colors.dimmed',
65
+ _light: 'mantine.colors.gray[5]',
66
+ _groupHover: 'mantine.colors.primary[0]',
67
+ _groupFocus: 'mantine.colors.primary[0]',
68
+ },
69
+ [_treenodefocus]: {
70
+ color: 'mantine.colors.primary[0]',
82
71
  },
83
72
  flex: `0 0 ${iconSize.ref}`,
84
73
  height: iconSize.ref,
@@ -116,23 +105,23 @@ const title = css.raw({
116
105
  opacity: 0.4,
117
106
  },
118
107
 
119
- // color: 'mantine.colors.dark[1]',
120
- // _groupHover: {
121
- // color: 'mantine.colors.primary[1]',
122
- // },
123
- // _groupFocus: {
124
- // color: 'mantine.colors.primary[1]',
125
- // },
126
- ...colors('mantine.colors.dark[1]', 'mantine.colors.primary[1]'),
127
- _light: {
128
- ...colors('mantine.colors.gray[6]', 'mantine.colors.primary[3]'),
129
- // color: `mantine.colors.gray[6]`,
130
- // _groupHover: {
131
- // color: 'mantine.colors.primary[3]',
132
- // },
133
- // _groupFocus: {
134
- // color: 'mantine.colors.primary[3]',
135
- // },
108
+ color: {
109
+ base: 'mantine.colors.dark[1]',
110
+ _light: 'mantine.colors.gray[7]',
111
+ _groupHover: {
112
+ base: 'mantine.colors.primary[1]',
113
+ _light: 'mantine.colors.white',
114
+ },
115
+ _groupFocus: {
116
+ base: 'mantine.colors.primary[1]',
117
+ _light: 'mantine.colors.white',
118
+ },
119
+ },
120
+ [_treenodefocus]: {
121
+ color: {
122
+ base: 'mantine.colors.primary[1]',
123
+ _light: 'mantine.colors.white',
124
+ },
136
125
  },
137
126
  })
138
127
  const descriptionColor = css.raw({
@@ -1,44 +1,17 @@
1
1
  import { css } from '@likec4/styles/css'
2
2
  export { focusable } from './_shared.css'
3
3
 
4
- export const backdrop = css({
5
- position: 'fixed',
6
- zIndex: 900,
7
- inset: '0px',
8
- backgroundColor: '[rgb(34 34 34 / 0.95)]',
9
- backdropFilter: 'auto',
10
- backdropBlur: '10px',
11
- _light: {
12
- backgroundColor: '[rgb(255 255 255 / 0.92 )]',
13
- },
14
- })
15
- export const root = css({
16
- containerName: 'likec4-search',
17
- containerType: 'size',
18
- position: 'fixed',
19
- zIndex: 901,
20
- top: 0,
21
- left: 0,
22
- width: '100%',
23
- height: '100%',
24
- maxHeight: '100vh',
25
- overflow: 'hidden',
26
- display: 'flex',
27
- flexDirection: 'column',
28
- justifyContent: 'stretch',
29
- gap: 'md',
30
- paddingTop: '32px',
31
- paddingLeft: '16px',
32
- paddingRight: '16px',
33
- paddingBottom: 0,
34
- })
35
4
  export const input = css({
36
5
  border: 'transparent',
37
- background: 'transparent',
38
- _focusWithin: {
39
- background: `mantine.colors.gray[3]/55`,
40
- _dark: {
41
- background: `mantine.colors.dark[4]/55`,
6
+ background: {
7
+ base: 'transparent',
8
+ _focusWithin: {
9
+ base: `mantine.colors.gray[4]/55 !important`,
10
+ _dark: `mantine.colors.dark[5]/55 !important`,
11
+ },
12
+ _groupHover: {
13
+ base: 'mantine.colors.gray[3]/35',
14
+ _dark: 'mantine.colors.dark[5]/35',
42
15
  },
43
16
  },
44
17
  })
@@ -1,3 +1,5 @@
1
+ import { focusable } from './_shared.css'
2
+
1
3
  export function stopAndPrevent(e: React.KeyboardEvent | KeyboardEvent) {
2
4
  e.stopPropagation()
3
5
  e.preventDefault()
@@ -18,3 +20,8 @@ export function moveFocusToSearchInput() {
18
20
  input.setSelectionRange(length, length)
19
21
  }
20
22
  }
23
+
24
+ export function focusToFirstFoundElement() {
25
+ let firstFoundElement = document.querySelector<HTMLButtonElement>(`[data-likec4-search] .${focusable}`)
26
+ firstFoundElement?.focus()
27
+ }
@@ -0,0 +1,41 @@
1
+ import { createSafeContext } from '@mantine/core'
2
+ import { useSelector } from '@xstate/react'
3
+ import { useCallback, useDeferredValue } from 'react'
4
+ import type { SearchActorRef, SearchActorSnapshot } from './searchActor'
5
+
6
+ export const [SearchActorContext, useSearchActor] = createSafeContext<{
7
+ searchActorRef: SearchActorRef
8
+ close: (cb?: () => void) => void
9
+ }>('SearchActorContext')
10
+
11
+ const selectSearchValue = (s: SearchActorSnapshot) => s.context.searchValue
12
+ export function useSearch(): [string, (search: string) => void] {
13
+ const { searchActorRef } = useSearchActor()
14
+ const searchValue = useSelector(searchActorRef, selectSearchValue)
15
+ const updateSearch = useCallback((search: string) => {
16
+ searchActorRef.send({ type: 'change.search', search })
17
+ }, [searchActorRef])
18
+ return [searchValue, updateSearch]
19
+ }
20
+
21
+ const selectNormalizedSearchValue = (s: SearchActorSnapshot) => {
22
+ const v = s.context.searchValue.trim().toLowerCase()
23
+ return v.length > 1 ? v : ''
24
+ }
25
+ export function useNormalizedSearch() {
26
+ const { searchActorRef } = useSearchActor()
27
+ return useDeferredValue(useSelector(searchActorRef, selectNormalizedSearchValue))
28
+ }
29
+
30
+ export function useUpdateSearch() {
31
+ const { searchActorRef } = useSearchActor()
32
+ return useCallback((search: string) => {
33
+ searchActorRef.send({ type: 'change.search', search })
34
+ }, [searchActorRef])
35
+ }
36
+
37
+ const selectPickViewFor = (s: SearchActorSnapshot) => s.context.pickViewFor
38
+ export function usePickViewFor() {
39
+ const { searchActorRef } = useSearchActor()
40
+ return useSelector(searchActorRef, selectPickViewFor)
41
+ }
@@ -0,0 +1,99 @@
1
+ import type { Fqn } from '@likec4/core/types'
2
+ import {
3
+ type ActorLogicFrom,
4
+ type ActorRefFrom,
5
+ type SnapshotFrom,
6
+ assertEvent,
7
+ assign,
8
+ setup,
9
+ } from 'xstate'
10
+
11
+ export type SearchActorEvent =
12
+ | { type: 'open'; search?: string | undefined }
13
+ | { type: 'close' }
14
+ | { type: 'change.search'; search: string }
15
+ | { type: 'pickview.open'; elementFqn: Fqn }
16
+ | { type: 'pickview.close' }
17
+
18
+ export interface SearchContext {
19
+ openedWithSearch: string | null
20
+ searchValue: string
21
+ pickViewFor: Fqn | null
22
+ }
23
+
24
+ const _searchActorLogic = setup({
25
+ types: {
26
+ context: {} as SearchContext,
27
+ events: {} as SearchActorEvent,
28
+ },
29
+ actions: {
30
+ 'change searchValue': assign({
31
+ searchValue: ({ event, context }) => {
32
+ assertEvent(event, ['change.search', 'open'])
33
+ return event.search ?? context.searchValue
34
+ },
35
+ }),
36
+ 'reset pickViewFor': assign({
37
+ pickViewFor: () => null,
38
+ }),
39
+ },
40
+ }).createMachine({
41
+ id: 'search',
42
+ context: {
43
+ openedWithSearch: null,
44
+ searchValue: '',
45
+ pickViewFor: null,
46
+ },
47
+ initial: 'inactive',
48
+ on: {
49
+ 'close': {
50
+ target: '.inactive',
51
+ actions: 'reset pickViewFor',
52
+ },
53
+ },
54
+ states: {
55
+ inactive: {
56
+ on: {
57
+ 'open': {
58
+ target: 'opened',
59
+ actions: [
60
+ assign({
61
+ openedWithSearch: ({ event }) => event.search ?? null,
62
+ searchValue: ({ event, context }) => event.search ?? context.searchValue,
63
+ }),
64
+ ],
65
+ },
66
+ },
67
+ },
68
+ opened: {
69
+ on: {
70
+ 'open': {
71
+ actions: 'change searchValue',
72
+ },
73
+ 'change.search': {
74
+ actions: 'change searchValue',
75
+ },
76
+ 'pickview.open': {
77
+ target: 'pickView',
78
+ actions: assign({
79
+ pickViewFor: ({ event }) => event.elementFqn,
80
+ }),
81
+ },
82
+ },
83
+ },
84
+ pickView: {
85
+ on: {
86
+ 'pickview.close': {
87
+ target: 'opened',
88
+ actions: 'reset pickViewFor',
89
+ },
90
+ },
91
+ },
92
+ },
93
+ })
94
+
95
+ export interface SearchActorLogic extends ActorLogicFrom<typeof _searchActorLogic> {}
96
+ export const searchActorLogic: SearchActorLogic = _searchActorLogic
97
+
98
+ export type SearchActorSnapshot = SnapshotFrom<SearchActorLogic>
99
+ export interface SearchActorRef extends ActorRefFrom<SearchActorLogic> {}