@furystack/shades-common-components 10.0.35 → 11.0.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 (295) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/esm/components/animations.spec.d.ts +2 -0
  3. package/esm/components/animations.spec.d.ts.map +1 -0
  4. package/esm/components/animations.spec.js +201 -0
  5. package/esm/components/animations.spec.js.map +1 -0
  6. package/esm/components/app-bar-link.js +21 -20
  7. package/esm/components/app-bar-link.js.map +1 -1
  8. package/esm/components/app-bar-link.spec.d.ts +2 -0
  9. package/esm/components/app-bar-link.spec.d.ts.map +1 -0
  10. package/esm/components/app-bar-link.spec.js +252 -0
  11. package/esm/components/app-bar-link.spec.js.map +1 -0
  12. package/esm/components/app-bar.js +21 -21
  13. package/esm/components/app-bar.js.map +1 -1
  14. package/esm/components/app-bar.spec.d.ts +2 -0
  15. package/esm/components/app-bar.spec.d.ts.map +1 -0
  16. package/esm/components/app-bar.spec.js +117 -0
  17. package/esm/components/app-bar.spec.js.map +1 -0
  18. package/esm/components/avatar.d.ts.map +1 -1
  19. package/esm/components/avatar.js +15 -19
  20. package/esm/components/avatar.js.map +1 -1
  21. package/esm/components/avatar.spec.d.ts +2 -0
  22. package/esm/components/avatar.spec.d.ts.map +1 -0
  23. package/esm/components/avatar.spec.js +114 -0
  24. package/esm/components/avatar.spec.js.map +1 -0
  25. package/esm/components/button.d.ts.map +1 -1
  26. package/esm/components/button.js +145 -156
  27. package/esm/components/button.js.map +1 -1
  28. package/esm/components/button.spec.d.ts +2 -0
  29. package/esm/components/button.spec.d.ts.map +1 -0
  30. package/esm/components/button.spec.js +155 -0
  31. package/esm/components/button.spec.js.map +1 -0
  32. package/esm/components/command-palette/command-palette-input.d.ts.map +1 -1
  33. package/esm/components/command-palette/command-palette-input.js +18 -16
  34. package/esm/components/command-palette/command-palette-input.js.map +1 -1
  35. package/esm/components/command-palette/command-palette-input.spec.d.ts +2 -0
  36. package/esm/components/command-palette/command-palette-input.spec.d.ts.map +1 -0
  37. package/esm/components/command-palette/command-palette-input.spec.js +233 -0
  38. package/esm/components/command-palette/command-palette-input.spec.js.map +1 -0
  39. package/esm/components/command-palette/command-palette-manager.spec.d.ts +2 -0
  40. package/esm/components/command-palette/command-palette-manager.spec.d.ts.map +1 -0
  41. package/esm/components/command-palette/command-palette-manager.spec.js +362 -0
  42. package/esm/components/command-palette/command-palette-manager.spec.js.map +1 -0
  43. package/esm/components/command-palette/command-palette-suggestion-list.d.ts.map +1 -1
  44. package/esm/components/command-palette/command-palette-suggestion-list.js +42 -46
  45. package/esm/components/command-palette/command-palette-suggestion-list.js.map +1 -1
  46. package/esm/components/command-palette/command-palette-suggestion-list.spec.d.ts +2 -0
  47. package/esm/components/command-palette/command-palette-suggestion-list.spec.d.ts.map +1 -0
  48. package/esm/components/command-palette/command-palette-suggestion-list.spec.js +376 -0
  49. package/esm/components/command-palette/command-palette-suggestion-list.spec.js.map +1 -0
  50. package/esm/components/command-palette/index.d.ts.map +1 -1
  51. package/esm/components/command-palette/index.js +100 -110
  52. package/esm/components/command-palette/index.js.map +1 -1
  53. package/esm/components/command-palette/index.spec.d.ts +2 -0
  54. package/esm/components/command-palette/index.spec.d.ts.map +1 -0
  55. package/esm/components/command-palette/index.spec.js +509 -0
  56. package/esm/components/command-palette/index.spec.js.map +1 -0
  57. package/esm/components/data-grid/body.js +1 -1
  58. package/esm/components/data-grid/body.js.map +1 -1
  59. package/esm/components/data-grid/body.spec.d.ts +2 -0
  60. package/esm/components/data-grid/body.spec.d.ts.map +1 -0
  61. package/esm/components/data-grid/body.spec.js +228 -0
  62. package/esm/components/data-grid/body.spec.js.map +1 -0
  63. package/esm/components/data-grid/data-grid-row.d.ts.map +1 -1
  64. package/esm/components/data-grid/data-grid-row.js +49 -73
  65. package/esm/components/data-grid/data-grid-row.js.map +1 -1
  66. package/esm/components/data-grid/data-grid-row.spec.d.ts +2 -0
  67. package/esm/components/data-grid/data-grid-row.spec.d.ts.map +1 -0
  68. package/esm/components/data-grid/data-grid-row.spec.js +296 -0
  69. package/esm/components/data-grid/data-grid-row.spec.js.map +1 -0
  70. package/esm/components/data-grid/data-grid.d.ts.map +1 -1
  71. package/esm/components/data-grid/data-grid.js +35 -28
  72. package/esm/components/data-grid/data-grid.js.map +1 -1
  73. package/esm/components/data-grid/data-grid.spec.d.ts +2 -0
  74. package/esm/components/data-grid/data-grid.spec.d.ts.map +1 -0
  75. package/esm/components/data-grid/data-grid.spec.js +544 -0
  76. package/esm/components/data-grid/data-grid.spec.js.map +1 -0
  77. package/esm/components/data-grid/footer.js +21 -15
  78. package/esm/components/data-grid/footer.js.map +1 -1
  79. package/esm/components/data-grid/footer.spec.d.ts +2 -0
  80. package/esm/components/data-grid/footer.spec.d.ts.map +1 -0
  81. package/esm/components/data-grid/footer.spec.js +264 -0
  82. package/esm/components/data-grid/footer.spec.js.map +1 -0
  83. package/esm/components/data-grid/header.d.ts.map +1 -1
  84. package/esm/components/data-grid/header.js +55 -33
  85. package/esm/components/data-grid/header.js.map +1 -1
  86. package/esm/components/data-grid/header.spec.d.ts +2 -0
  87. package/esm/components/data-grid/header.spec.d.ts.map +1 -0
  88. package/esm/components/data-grid/header.spec.js +421 -0
  89. package/esm/components/data-grid/header.spec.js.map +1 -0
  90. package/esm/components/data-grid/selection-cell.d.ts.map +1 -1
  91. package/esm/components/data-grid/selection-cell.js +13 -6
  92. package/esm/components/data-grid/selection-cell.js.map +1 -1
  93. package/esm/components/data-grid/selection-cell.spec.d.ts +2 -0
  94. package/esm/components/data-grid/selection-cell.spec.d.ts.map +1 -0
  95. package/esm/components/data-grid/selection-cell.spec.js +118 -0
  96. package/esm/components/data-grid/selection-cell.spec.js.map +1 -0
  97. package/esm/components/fab.d.ts.map +1 -1
  98. package/esm/components/fab.js +10 -1
  99. package/esm/components/fab.js.map +1 -1
  100. package/esm/components/fab.spec.d.ts +2 -0
  101. package/esm/components/fab.spec.d.ts.map +1 -0
  102. package/esm/components/fab.spec.js +95 -0
  103. package/esm/components/fab.spec.js.map +1 -0
  104. package/esm/components/form.spec.d.ts +2 -0
  105. package/esm/components/form.spec.d.ts.map +1 -0
  106. package/esm/components/form.spec.js +314 -0
  107. package/esm/components/form.spec.js.map +1 -0
  108. package/esm/components/grid.d.ts.map +1 -1
  109. package/esm/components/grid.js +40 -37
  110. package/esm/components/grid.js.map +1 -1
  111. package/esm/components/grid.spec.d.ts +2 -0
  112. package/esm/components/grid.spec.d.ts.map +1 -0
  113. package/esm/components/grid.spec.js +316 -0
  114. package/esm/components/grid.spec.js.map +1 -0
  115. package/esm/components/inputs/autocomplete.spec.d.ts +2 -0
  116. package/esm/components/inputs/autocomplete.spec.d.ts.map +1 -0
  117. package/esm/components/inputs/autocomplete.spec.js +194 -0
  118. package/esm/components/inputs/autocomplete.spec.js.map +1 -0
  119. package/esm/components/inputs/input.d.ts.map +1 -1
  120. package/esm/components/inputs/input.js +141 -109
  121. package/esm/components/inputs/input.js.map +1 -1
  122. package/esm/components/inputs/input.spec.d.ts +2 -0
  123. package/esm/components/inputs/input.spec.d.ts.map +1 -0
  124. package/esm/components/inputs/input.spec.js +577 -0
  125. package/esm/components/inputs/input.spec.js.map +1 -0
  126. package/esm/components/inputs/text-area.d.ts.map +1 -1
  127. package/esm/components/inputs/text-area.js +54 -58
  128. package/esm/components/inputs/text-area.js.map +1 -1
  129. package/esm/components/inputs/text-area.spec.d.ts +2 -0
  130. package/esm/components/inputs/text-area.spec.d.ts.map +1 -0
  131. package/esm/components/inputs/text-area.spec.js +214 -0
  132. package/esm/components/inputs/text-area.spec.js.map +1 -0
  133. package/esm/components/loader.js +1 -1
  134. package/esm/components/loader.js.map +1 -1
  135. package/esm/components/loader.spec.d.ts +2 -0
  136. package/esm/components/loader.spec.d.ts.map +1 -0
  137. package/esm/components/loader.spec.js +251 -0
  138. package/esm/components/loader.spec.js.map +1 -0
  139. package/esm/components/modal.d.ts.map +1 -1
  140. package/esm/components/modal.js +11 -9
  141. package/esm/components/modal.js.map +1 -1
  142. package/esm/components/modal.spec.d.ts +2 -0
  143. package/esm/components/modal.spec.d.ts.map +1 -0
  144. package/esm/components/modal.spec.js +227 -0
  145. package/esm/components/modal.spec.js.map +1 -0
  146. package/esm/components/noty-list.d.ts.map +1 -1
  147. package/esm/components/noty-list.js +39 -40
  148. package/esm/components/noty-list.js.map +1 -1
  149. package/esm/components/noty-list.spec.d.ts +2 -0
  150. package/esm/components/noty-list.spec.d.ts.map +1 -0
  151. package/esm/components/noty-list.spec.js +486 -0
  152. package/esm/components/noty-list.spec.js.map +1 -0
  153. package/esm/components/paper.d.ts.map +1 -1
  154. package/esm/components/paper.js +15 -12
  155. package/esm/components/paper.js.map +1 -1
  156. package/esm/components/paper.spec.d.ts +2 -0
  157. package/esm/components/paper.spec.d.ts.map +1 -0
  158. package/esm/components/paper.spec.js +63 -0
  159. package/esm/components/paper.spec.js.map +1 -0
  160. package/esm/components/skeleton.js +1 -1
  161. package/esm/components/skeleton.js.map +1 -1
  162. package/esm/components/skeleton.spec.d.ts +2 -0
  163. package/esm/components/skeleton.spec.d.ts.map +1 -0
  164. package/esm/components/skeleton.spec.js +159 -0
  165. package/esm/components/skeleton.spec.js.map +1 -0
  166. package/esm/components/styles.spec.d.ts +2 -0
  167. package/esm/components/styles.spec.d.ts.map +1 -0
  168. package/esm/components/styles.spec.js +56 -0
  169. package/esm/components/styles.spec.js.map +1 -0
  170. package/esm/components/suggest/index.d.ts.map +1 -1
  171. package/esm/components/suggest/index.js +74 -83
  172. package/esm/components/suggest/index.js.map +1 -1
  173. package/esm/components/suggest/index.spec.d.ts +2 -0
  174. package/esm/components/suggest/index.spec.d.ts.map +1 -0
  175. package/esm/components/suggest/index.spec.js +515 -0
  176. package/esm/components/suggest/index.spec.js.map +1 -0
  177. package/esm/components/suggest/suggest-input.d.ts.map +1 -1
  178. package/esm/components/suggest/suggest-input.js +16 -17
  179. package/esm/components/suggest/suggest-input.js.map +1 -1
  180. package/esm/components/suggest/suggest-input.spec.d.ts +2 -0
  181. package/esm/components/suggest/suggest-input.spec.d.ts.map +1 -0
  182. package/esm/components/suggest/suggest-input.spec.js +138 -0
  183. package/esm/components/suggest/suggest-input.spec.js.map +1 -0
  184. package/esm/components/suggest/suggest-manager.spec.d.ts +2 -0
  185. package/esm/components/suggest/suggest-manager.spec.d.ts.map +1 -0
  186. package/esm/components/suggest/suggest-manager.spec.js +308 -0
  187. package/esm/components/suggest/suggest-manager.spec.js.map +1 -0
  188. package/esm/components/suggest/suggestion-list.d.ts.map +1 -1
  189. package/esm/components/suggest/suggestion-list.js +43 -48
  190. package/esm/components/suggest/suggestion-list.js.map +1 -1
  191. package/esm/components/suggest/suggestion-list.spec.d.ts +2 -0
  192. package/esm/components/suggest/suggestion-list.spec.d.ts.map +1 -0
  193. package/esm/components/suggest/suggestion-list.spec.js +252 -0
  194. package/esm/components/suggest/suggestion-list.spec.js.map +1 -0
  195. package/esm/components/tabs.d.ts.map +1 -1
  196. package/esm/components/tabs.js +32 -18
  197. package/esm/components/tabs.js.map +1 -1
  198. package/esm/components/tabs.spec.d.ts +2 -0
  199. package/esm/components/tabs.spec.d.ts.map +1 -0
  200. package/esm/components/tabs.spec.js +187 -0
  201. package/esm/components/tabs.spec.js.map +1 -0
  202. package/esm/components/wizard/index.d.ts.map +1 -1
  203. package/esm/components/wizard/index.js +10 -7
  204. package/esm/components/wizard/index.js.map +1 -1
  205. package/esm/components/wizard/index.spec.d.ts +2 -0
  206. package/esm/components/wizard/index.spec.d.ts.map +1 -0
  207. package/esm/components/wizard/index.spec.js +171 -0
  208. package/esm/components/wizard/index.spec.js.map +1 -0
  209. package/esm/services/collection-service.spec.js +391 -2
  210. package/esm/services/collection-service.spec.js.map +1 -1
  211. package/esm/services/css-variable-theme.d.ts.map +1 -1
  212. package/esm/services/css-variable-theme.js +21 -1
  213. package/esm/services/css-variable-theme.js.map +1 -1
  214. package/esm/services/css-variable-theme.spec.d.ts +2 -0
  215. package/esm/services/css-variable-theme.spec.d.ts.map +1 -0
  216. package/esm/services/css-variable-theme.spec.js +169 -0
  217. package/esm/services/css-variable-theme.spec.js.map +1 -0
  218. package/esm/services/default-palette.d.ts +4 -0
  219. package/esm/services/default-palette.d.ts.map +1 -1
  220. package/esm/services/default-palette.js +22 -0
  221. package/esm/services/default-palette.js.map +1 -1
  222. package/esm/services/theme-provider-service.d.ts +59 -1
  223. package/esm/services/theme-provider-service.d.ts.map +1 -1
  224. package/esm/services/theme-provider-service.js.map +1 -1
  225. package/esm/services/theme-provider-service.spec.d.ts +2 -0
  226. package/esm/services/theme-provider-service.spec.d.ts.map +1 -0
  227. package/esm/services/theme-provider-service.spec.js +166 -0
  228. package/esm/services/theme-provider-service.spec.js.map +1 -0
  229. package/package.json +2 -2
  230. package/src/components/animations.spec.ts +299 -0
  231. package/src/components/app-bar-link.spec.tsx +341 -0
  232. package/src/components/app-bar-link.tsx +21 -21
  233. package/src/components/app-bar.spec.tsx +142 -0
  234. package/src/components/app-bar.tsx +22 -22
  235. package/src/components/avatar.spec.tsx +146 -0
  236. package/src/components/avatar.tsx +17 -20
  237. package/src/components/button.spec.tsx +193 -0
  238. package/src/components/button.tsx +162 -197
  239. package/src/components/command-palette/command-palette-input.spec.tsx +320 -0
  240. package/src/components/command-palette/command-palette-input.tsx +19 -22
  241. package/src/components/command-palette/command-palette-manager.spec.ts +470 -0
  242. package/src/components/command-palette/command-palette-suggestion-list.spec.tsx +499 -0
  243. package/src/components/command-palette/command-palette-suggestion-list.tsx +42 -46
  244. package/src/components/command-palette/index.spec.tsx +684 -0
  245. package/src/components/command-palette/index.tsx +107 -136
  246. package/src/components/data-grid/body.spec.tsx +340 -0
  247. package/src/components/data-grid/body.tsx +1 -1
  248. package/src/components/data-grid/data-grid-row.spec.tsx +382 -0
  249. package/src/components/data-grid/data-grid-row.tsx +50 -82
  250. package/src/components/data-grid/data-grid.spec.tsx +939 -0
  251. package/src/components/data-grid/data-grid.tsx +38 -35
  252. package/src/components/data-grid/footer.spec.tsx +344 -0
  253. package/src/components/data-grid/footer.tsx +19 -19
  254. package/src/components/data-grid/header.spec.tsx +563 -0
  255. package/src/components/data-grid/header.tsx +53 -44
  256. package/src/components/data-grid/selection-cell.spec.tsx +150 -0
  257. package/src/components/data-grid/selection-cell.tsx +12 -6
  258. package/src/components/fab.spec.tsx +108 -0
  259. package/src/components/fab.tsx +10 -1
  260. package/src/components/form.spec.tsx +481 -0
  261. package/src/components/grid.spec.tsx +334 -0
  262. package/src/components/grid.tsx +57 -63
  263. package/src/components/inputs/autocomplete.spec.tsx +258 -0
  264. package/src/components/inputs/input.spec.tsx +808 -0
  265. package/src/components/inputs/input.tsx +153 -139
  266. package/src/components/inputs/text-area.spec.tsx +285 -0
  267. package/src/components/inputs/text-area.tsx +53 -79
  268. package/src/components/loader.spec.tsx +346 -0
  269. package/src/components/loader.tsx +1 -1
  270. package/src/components/modal.spec.tsx +304 -0
  271. package/src/components/modal.tsx +11 -9
  272. package/src/components/noty-list.spec.tsx +631 -0
  273. package/src/components/noty-list.tsx +39 -50
  274. package/src/components/paper.spec.tsx +72 -0
  275. package/src/components/paper.tsx +15 -13
  276. package/src/components/skeleton.spec.tsx +219 -0
  277. package/src/components/skeleton.tsx +1 -1
  278. package/src/components/styles.spec.ts +70 -0
  279. package/src/components/suggest/index.spec.tsx +861 -0
  280. package/src/components/suggest/index.tsx +74 -101
  281. package/src/components/suggest/suggest-input.spec.tsx +181 -0
  282. package/src/components/suggest/suggest-input.tsx +16 -24
  283. package/src/components/suggest/suggest-manager.spec.ts +409 -0
  284. package/src/components/suggest/suggestion-list.spec.tsx +334 -0
  285. package/src/components/suggest/suggestion-list.tsx +43 -48
  286. package/src/components/tabs.spec.tsx +236 -0
  287. package/src/components/tabs.tsx +33 -21
  288. package/src/components/wizard/index.spec.tsx +224 -0
  289. package/src/components/wizard/index.tsx +10 -9
  290. package/src/services/collection-service.spec.ts +492 -3
  291. package/src/services/css-variable-theme.spec.ts +204 -0
  292. package/src/services/css-variable-theme.ts +21 -1
  293. package/src/services/default-palette.ts +22 -0
  294. package/src/services/theme-provider-service.spec.ts +195 -0
  295. package/src/services/theme-provider-service.ts +60 -2
@@ -1,6 +1,6 @@
1
1
  import type { ChildrenList } from '@furystack/shades'
2
2
  import { Shade, createComponent } from '@furystack/shades'
3
- import { ThemeProviderService } from '../../services/theme-provider-service.js'
3
+ import { cssVariableTheme } from '../../services/css-variable-theme.js'
4
4
  import { promisifyAnimation } from '../../utils/promisify-animation.js'
5
5
  import { Loader } from '../loader.js'
6
6
  import { SuggestInput } from './suggest-input.js'
@@ -25,32 +25,84 @@ export const Suggest: <T>(props: SuggestProps<T>, children: ChildrenList) => JSX
25
25
  SuggestProps<any>
26
26
  >({
27
27
  shadowDomName: 'shade-suggest',
28
- style: {
28
+ css: {
29
29
  flexGrow: '1',
30
+ '& .suggest-wrapper': {
31
+ display: 'flex',
32
+ flexDirection: 'column',
33
+ },
34
+ '& .input-container': {
35
+ display: 'flex',
36
+ alignItems: 'center',
37
+ justifyContent: 'flex-end',
38
+ padding: '0 1.25em',
39
+ borderRadius: '12px',
40
+ position: 'relative',
41
+ background: 'rgba(128,128,128,0.08)',
42
+ border: '1px solid rgba(128,128,128,0.15)',
43
+ boxShadow: '0 2px 4px rgba(0,0,0,0.05)',
44
+ transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
45
+ },
46
+ '&.opened .input-container': {
47
+ border: '1px solid rgba(128,128,128,0.3)',
48
+ boxShadow: '0 4px 12px rgba(0,0,0,0.15), 0 0 0 3px rgba(128,128,128,0.05)',
49
+ },
50
+ '& .term-icon': {
51
+ cursor: 'pointer',
52
+ color: cssVariableTheme.text.secondary,
53
+ fontWeight: '600',
54
+ fontSize: '0.95em',
55
+ transition: 'color 0.2s ease',
56
+ padding: '0.5em 0.75em 0.5em 0',
57
+ userSelect: 'none',
58
+ },
59
+ '& .term-icon:hover': {
60
+ color: cssVariableTheme.text.primary,
61
+ },
62
+ '& .post-controls': {
63
+ display: 'flex',
64
+ alignItems: 'center',
65
+ justifyContent: 'space-between',
66
+ width: '0px',
67
+ overflow: 'hidden',
68
+ },
69
+ '&.opened .post-controls': {
70
+ width: '50px',
71
+ },
72
+ '& .close-suggestions': {
73
+ width: '24px',
74
+ height: '24px',
75
+ opacity: '0',
76
+ display: 'flex',
77
+ alignItems: 'center',
78
+ justifyContent: 'center',
79
+ cursor: 'pointer',
80
+ borderRadius: '6px',
81
+ transition: 'all 0.2s ease',
82
+ fontSize: '14px',
83
+ color: cssVariableTheme.text.secondary,
84
+ background: 'transparent',
85
+ transform: 'scale(1)',
86
+ },
87
+ '&.opened .close-suggestions': {
88
+ opacity: '1',
89
+ },
90
+ '& .close-suggestions:hover': {
91
+ background: 'rgba(255,255,255,0.15)',
92
+ transform: 'scale(1.1)',
93
+ },
30
94
  },
31
95
  render: ({ props, injector, element, useDisposable }) => {
32
96
  const manager = useDisposable('manager', () => new SuggestManager(props.getEntries, props.getSuggestionEntry))
33
- const { theme } = injector.getInstance(ThemeProviderService)
34
97
  manager.element = element
35
98
  manager.isOpened.subscribe((isOpened) => {
99
+ element.classList.toggle('opened', isOpened)
36
100
  const inputContainer = element.querySelector('.input-container') as HTMLDivElement
37
101
 
38
- const suggestions = element.querySelector('.close-suggestions')
39
- const postControls = element.querySelector('.post-controls')
40
102
  if (isOpened) {
41
- void promisifyAnimation(suggestions, [{ opacity: 0 }, { opacity: 1 }], {
42
- duration: 500,
43
- fill: 'forwards',
44
- })
45
-
46
- void promisifyAnimation(postControls, [{ width: '0px' }, { width: '50px' }], {
47
- duration: 100,
48
- fill: 'forwards',
49
- })
50
-
51
103
  void promisifyAnimation(
52
104
  inputContainer,
53
- [{ background: 'transparent' }, { background: theme.background.default }],
105
+ [{ background: 'transparent' }, { background: cssVariableTheme.background.default }],
54
106
  {
55
107
  duration: 500,
56
108
  fill: 'forwards',
@@ -58,20 +110,9 @@ export const Suggest: <T>(props: SuggestProps<T>, children: ChildrenList) => JSX
58
110
  },
59
111
  )
60
112
  } else {
61
- void promisifyAnimation(suggestions, [{ opacity: 1 }, { opacity: 0 }], {
62
- duration: 500,
63
- fill: 'forwards',
64
- })
65
-
66
- void promisifyAnimation(postControls, [{ width: '50px' }, { width: '0px' }], {
67
- duration: 500,
68
- fill: 'forwards',
69
- delay: 300,
70
- })
71
-
72
113
  void promisifyAnimation(
73
114
  inputContainer,
74
- [{ background: theme.background.default }, { background: 'transparent' }],
115
+ [{ background: cssVariableTheme.background.default }, { background: 'transparent' }],
75
116
  {
76
117
  duration: 300,
77
118
  fill: 'forwards',
@@ -97,7 +138,7 @@ export const Suggest: <T>(props: SuggestProps<T>, children: ChildrenList) => JSX
97
138
  useDisposable('onSelectSuggestion', () => manager.subscribe('onSelectSuggestion', props.onSelectSuggestion))
98
139
  return (
99
140
  <div
100
- style={{ display: 'flex', flexDirection: 'column' }}
141
+ className="suggest-wrapper"
101
142
  onkeyup={(ev) => {
102
143
  if (ev.key === 'Enter') {
103
144
  ev.preventDefault()
@@ -118,86 +159,18 @@ export const Suggest: <T>(props: SuggestProps<T>, children: ChildrenList) => JSX
118
159
  void manager.getSuggestion({ injector, term: (ev.target as HTMLInputElement).value })
119
160
  }}
120
161
  >
121
- <div
122
- className="input-container"
123
- style={{
124
- display: 'flex',
125
- alignItems: 'center',
126
- justifyContent: 'flex-end',
127
- padding: '0 1.25em',
128
- borderRadius: '12px',
129
- position: 'relative',
130
- background: 'rgba(128,128,128,0.08)',
131
- border: `1px solid ${manager.isOpened.getValue() ? 'rgba(128,128,128,0.3)' : 'rgba(128,128,128,0.15)'}`,
132
- boxShadow: manager.isOpened.getValue()
133
- ? '0 4px 12px rgba(0,0,0,0.15), 0 0 0 3px rgba(128,128,128,0.05)'
134
- : '0 2px 4px rgba(0,0,0,0.05)',
135
- transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
136
- ...props.style,
137
- }}
138
- >
139
- <div
140
- className="term-icon"
141
- style={{
142
- cursor: 'pointer',
143
- color: theme.text.secondary,
144
- fontWeight: '600',
145
- fontSize: '0.95em',
146
- transition: 'color 0.2s ease',
147
- padding: '0.5em 0.75em 0.5em 0',
148
- userSelect: 'none',
149
- }}
150
- onmouseenter={(ev) => {
151
- ;(ev.target as HTMLElement).style.color = theme.text.primary
152
- }}
153
- onmouseleave={(ev) => {
154
- ;(ev.target as HTMLElement).style.color = theme.text.secondary
155
- }}
156
- onclick={() => manager.isOpened.setValue(true)}
157
- >
162
+ <div className="input-container" style={props.style}>
163
+ <div className="term-icon" onclick={() => manager.isOpened.setValue(true)}>
158
164
  {props.defaultPrefix}
159
165
  </div>
160
166
  <SuggestInput manager={manager} />
161
- <div
162
- className="post-controls"
163
- style={{
164
- display: 'flex',
165
- alignItems: 'center',
166
- justifyContent: 'space-between',
167
- width: manager.isOpened.getValue() ? '50px' : '0px',
168
- overflow: 'hidden',
169
- }}
170
- >
167
+ <div className="post-controls">
171
168
  <Loader
172
169
  style={{ width: '20px', height: '20px', opacity: manager.isLoading.getValue() ? '1' : '0' }}
173
170
  delay={0}
174
171
  borderWidth={4}
175
172
  />
176
- <div
177
- className="close-suggestions"
178
- onclick={() => manager.isOpened.setValue(false)}
179
- onmouseenter={(ev) => {
180
- ;(ev.target as HTMLElement).style.background = 'rgba(255,255,255,0.15)'
181
- ;(ev.target as HTMLElement).style.transform = 'scale(1.1)'
182
- }}
183
- onmouseleave={(ev) => {
184
- ;(ev.target as HTMLElement).style.background = 'transparent'
185
- ;(ev.target as HTMLElement).style.transform = 'scale(1)'
186
- }}
187
- style={{
188
- width: '24px',
189
- height: '24px',
190
- opacity: manager.isOpened.getValue() ? '1' : '0',
191
- display: 'flex',
192
- alignItems: 'center',
193
- justifyContent: 'center',
194
- cursor: 'pointer',
195
- borderRadius: '6px',
196
- transition: 'all 0.2s ease',
197
- fontSize: '14px',
198
- color: theme.text.secondary,
199
- }}
200
- >
173
+ <div className="close-suggestions" onclick={() => manager.isOpened.setValue(false)}>
201
174
 
202
175
  </div>
203
176
  </div>
@@ -0,0 +1,181 @@
1
+ import { Injector } from '@furystack/inject'
2
+ import { createComponent, initializeShadeRoot } from '@furystack/shades'
3
+ import { sleepAsync, using } from '@furystack/utils'
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
5
+ import { SuggestInput } from './suggest-input.js'
6
+ import { SuggestManager } from './suggest-manager.js'
7
+ import type { SuggestionResult } from './suggestion-result.js'
8
+
9
+ type TestEntry = { id: number; name: string }
10
+
11
+ const createSuggestionResult = (entry: TestEntry): SuggestionResult => ({
12
+ element: (<div>{entry.name}</div>) as unknown as JSX.Element,
13
+ score: entry.id,
14
+ })
15
+
16
+ describe('SuggestInput', () => {
17
+ let originalAnimate: typeof Element.prototype.animate
18
+
19
+ beforeEach(() => {
20
+ document.body.innerHTML = '<div id="root"></div>'
21
+ originalAnimate = Element.prototype.animate
22
+
23
+ Element.prototype.animate = vi.fn(() => {
24
+ const mockAnimation = {
25
+ onfinish: null as ((event: AnimationPlaybackEvent) => void) | null,
26
+ oncancel: null as ((event: AnimationPlaybackEvent) => void) | null,
27
+ cancel: vi.fn(),
28
+ play: vi.fn(),
29
+ pause: vi.fn(),
30
+ finish: vi.fn(),
31
+ addEventListener: vi.fn(),
32
+ removeEventListener: vi.fn(),
33
+ }
34
+ return mockAnimation as unknown as Animation
35
+ }) as typeof Element.prototype.animate
36
+ })
37
+
38
+ afterEach(() => {
39
+ document.body.innerHTML = ''
40
+ Element.prototype.animate = originalAnimate
41
+ vi.restoreAllMocks()
42
+ })
43
+
44
+ const createManager = () => {
45
+ const getEntries = vi.fn().mockResolvedValue([])
46
+ const getSuggestionEntry = vi.fn().mockImplementation(createSuggestionResult)
47
+ return new SuggestManager<TestEntry>(getEntries, getSuggestionEntry)
48
+ }
49
+
50
+ it('should render with shadow DOM', async () => {
51
+ const injector = new Injector()
52
+ const rootElement = document.getElementById('root') as HTMLDivElement
53
+
54
+ using(createManager(), (manager) => {
55
+ initializeShadeRoot({
56
+ injector,
57
+ rootElement,
58
+ jsxElement: <SuggestInput manager={manager} />,
59
+ })
60
+ })
61
+
62
+ await sleepAsync(50)
63
+
64
+ const suggestInput = document.querySelector('shades-suggest-input')
65
+ expect(suggestInput).not.toBeNull()
66
+ })
67
+
68
+ it('should render the inner input element', async () => {
69
+ const injector = new Injector()
70
+ const rootElement = document.getElementById('root') as HTMLDivElement
71
+
72
+ using(createManager(), (manager) => {
73
+ initializeShadeRoot({
74
+ injector,
75
+ rootElement,
76
+ jsxElement: <SuggestInput manager={manager} />,
77
+ })
78
+ })
79
+
80
+ await sleepAsync(50)
81
+
82
+ const input = document.querySelector('shades-suggest-input input') as HTMLInputElement
83
+ expect(input).not.toBeNull()
84
+ expect(input.placeholder).toBe('Type to search...')
85
+ expect(input.autofocus).toBe(true)
86
+ })
87
+
88
+ it('should focus input when isOpened becomes true', async () => {
89
+ const injector = new Injector()
90
+ const rootElement = document.getElementById('root') as HTMLDivElement
91
+ const manager = createManager()
92
+
93
+ initializeShadeRoot({
94
+ injector,
95
+ rootElement,
96
+ jsxElement: <SuggestInput manager={manager} />,
97
+ })
98
+
99
+ await sleepAsync(50)
100
+
101
+ const input = document.querySelector('shades-suggest-input input') as HTMLInputElement
102
+ const focusSpy = vi.spyOn(input, 'focus')
103
+
104
+ manager.isOpened.setValue(true)
105
+ await sleepAsync(50)
106
+
107
+ expect(focusSpy).toHaveBeenCalled()
108
+
109
+ manager[Symbol.dispose]()
110
+ })
111
+
112
+ it('should clear input value when isOpened becomes false', async () => {
113
+ const injector = new Injector()
114
+ const rootElement = document.getElementById('root') as HTMLDivElement
115
+ const manager = createManager()
116
+
117
+ initializeShadeRoot({
118
+ injector,
119
+ rootElement,
120
+ jsxElement: <SuggestInput manager={manager} />,
121
+ })
122
+
123
+ await sleepAsync(50)
124
+
125
+ const input = document.querySelector('shades-suggest-input input') as HTMLInputElement
126
+ input.value = 'test query'
127
+
128
+ manager.isOpened.setValue(true)
129
+ await sleepAsync(50)
130
+
131
+ manager.isOpened.setValue(false)
132
+ await sleepAsync(50)
133
+
134
+ expect(input.value).toBe('')
135
+
136
+ manager[Symbol.dispose]()
137
+ })
138
+
139
+ it('should not clear input when first mounted with isOpened false', async () => {
140
+ const injector = new Injector()
141
+ const rootElement = document.getElementById('root') as HTMLDivElement
142
+ const manager = createManager()
143
+
144
+ initializeShadeRoot({
145
+ injector,
146
+ rootElement,
147
+ jsxElement: <SuggestInput manager={manager} />,
148
+ })
149
+
150
+ await sleepAsync(50)
151
+
152
+ const input = document.querySelector('shades-suggest-input input') as HTMLInputElement
153
+
154
+ input.value = 'initial value'
155
+ expect(input.value).toBe('initial value')
156
+
157
+ manager[Symbol.dispose]()
158
+ })
159
+
160
+ it('should have correct CSS styling applied', async () => {
161
+ const injector = new Injector()
162
+ const rootElement = document.getElementById('root') as HTMLDivElement
163
+ const manager = createManager()
164
+
165
+ initializeShadeRoot({
166
+ injector,
167
+ rootElement,
168
+ jsxElement: <SuggestInput manager={manager} />,
169
+ })
170
+
171
+ await sleepAsync(50)
172
+
173
+ const suggestInput = document.querySelector('shades-suggest-input') as HTMLElement
174
+ expect(suggestInput).not.toBeNull()
175
+
176
+ const input = suggestInput.querySelector('input') as HTMLInputElement
177
+ expect(input).not.toBeNull()
178
+
179
+ manager[Symbol.dispose]()
180
+ })
181
+ })
@@ -1,17 +1,26 @@
1
1
  import { Shade, createComponent } from '@furystack/shades'
2
- import { ThemeProviderService } from '../../services/theme-provider-service.js'
2
+ import { cssVariableTheme } from '../../services/css-variable-theme.js'
3
3
  import type { SuggestManager } from './suggest-manager.js'
4
4
 
5
5
  export const SuggestInput = Shade<{ manager: SuggestManager<any> }>({
6
6
  shadowDomName: 'shades-suggest-input',
7
- style: {
7
+ css: {
8
8
  width: '100%',
9
9
  overflow: 'hidden',
10
+ '& input': {
11
+ color: cssVariableTheme.text.primary,
12
+ outline: 'none',
13
+ padding: '0.875em 0.5em',
14
+ background: 'transparent',
15
+ border: 'none',
16
+ display: 'inline-flex',
17
+ width: 'calc(100% - 1em)',
18
+ fontSize: '0.95em',
19
+ fontWeight: '400',
20
+ letterSpacing: '0.01em',
21
+ },
10
22
  },
11
- render: ({ element, props, useObservable, injector }) => {
12
- const { theme } = injector.getInstance(ThemeProviderService)
13
-
14
- // todo: getLast is eliminated, do we need it?
23
+ render: ({ element, props, useObservable }) => {
15
24
  useObservable('isOpened', props.manager.isOpened, {
16
25
  onChange: (isOpened) => {
17
26
  const input = element.firstChild as HTMLInputElement
@@ -23,23 +32,6 @@ export const SuggestInput = Shade<{ manager: SuggestManager<any> }>({
23
32
  },
24
33
  })
25
34
 
26
- return (
27
- <input
28
- autofocus
29
- placeholder="Type to search..."
30
- style={{
31
- color: theme.text.primary,
32
- outline: 'none',
33
- padding: '0.875em 0.5em',
34
- background: 'transparent',
35
- border: 'none',
36
- display: 'inline-flex',
37
- width: 'calc(100% - 1em)',
38
- fontSize: '0.95em',
39
- fontWeight: '400',
40
- letterSpacing: '0.01em',
41
- }}
42
- />
43
- )
35
+ return <input autofocus placeholder="Type to search..." />
44
36
  },
45
37
  })