@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,10 +1,10 @@
1
1
  import type { FindOptions } from '@furystack/core'
2
2
  import type { ChildrenList } from '@furystack/shades'
3
- import { createComponent, Shade } from '@furystack/shades'
3
+ import { attachStyles, createComponent, Shade } from '@furystack/shades'
4
4
  import type { ObservableValue } from '@furystack/utils'
5
5
  import { ClickAwayService } from '../../services/click-away-service.js'
6
6
  import type { CollectionService } from '../../services/collection-service.js'
7
- import { ThemeProviderService } from '../../services/theme-provider-service.js'
7
+ import { cssVariableTheme } from '../../services/css-variable-theme.js'
8
8
  import type { GridProps } from '../grid.js'
9
9
  import { DataGridBody } from './body.js'
10
10
  import { DataGridFooter } from './footer.js'
@@ -80,27 +80,22 @@ export const DataGrid: <T, Column extends string>(
80
80
  children: ChildrenList,
81
81
  ) => JSX.Element<any> = Shade({
82
82
  shadowDomName: 'shade-data-grid',
83
- constructed: ({ props }) => {
84
- const listener = (ev: KeyboardEvent) => props.collectionService.handleKeyDown(ev)
85
- window.addEventListener('keydown', listener)
86
- return () => window.removeEventListener('keydown', listener)
87
- },
88
- render: ({ props, injector, useDisposable, element }) => {
89
- const tp = injector.getInstance(ThemeProviderService)
90
- const { theme } = tp
91
-
92
- useDisposable(
93
- 'clickAway',
94
- () =>
95
- new ClickAwayService(element, () => {
96
- props.collectionService.hasFocus.setValue(false)
97
- }),
98
- )
99
-
100
- const headerStyle: Partial<CSSStyleDeclaration> = {
83
+ css: {
84
+ display: 'block',
85
+ width: '100%',
86
+ height: '100%',
87
+ overflow: 'auto',
88
+ zIndex: '1',
89
+ '& table': {
90
+ width: '100%',
91
+ maxHeight: 'calc(100% - 4em)',
92
+ position: 'relative',
93
+ borderCollapse: 'collapse',
94
+ },
95
+ '& th': {
101
96
  backdropFilter: 'blur(12px) saturate(180%)',
102
97
  background: 'rgba(128,128,128,0.3)',
103
- color: theme.text.secondary,
98
+ color: cssVariableTheme.text.secondary,
104
99
  height: '48px',
105
100
  padding: '0 1.2em',
106
101
  alignItems: 'center',
@@ -114,34 +109,42 @@ export const DataGrid: <T, Column extends string>(
114
109
  textAlign: 'left',
115
110
  zIndex: '1',
116
111
  boxShadow: 'rgba(0, 0, 0, 0.2) 1px 1px 1px 2px',
117
- borderBottom: `2px solid rgba(128, 128, 128, 0.2)`,
118
- borderRight: `1px solid rgba(128, 128, 128, 0.2)`,
119
- ...props.styles?.header,
112
+ borderBottom: '2px solid rgba(128, 128, 128, 0.2)',
113
+ borderRight: '1px solid rgba(128, 128, 128, 0.2)',
114
+ },
115
+ },
116
+ constructed: ({ props }) => {
117
+ const listener = (ev: KeyboardEvent) => props.collectionService.handleKeyDown(ev)
118
+ window.addEventListener('keydown', listener)
119
+ return () => window.removeEventListener('keydown', listener)
120
+ },
121
+ render: ({ props, useDisposable, element }) => {
122
+ useDisposable(
123
+ 'clickAway',
124
+ () =>
125
+ new ClickAwayService(element, () => {
126
+ props.collectionService.hasFocus.setValue(false)
127
+ }),
128
+ )
129
+
130
+ if (props.styles?.wrapper) {
131
+ attachStyles(element, { style: props.styles.wrapper })
120
132
  }
121
133
 
122
134
  return (
123
135
  <div
124
136
  className="shade-grid-wrapper"
125
- style={{
126
- ...props.styles?.wrapper,
127
- width: '100%',
128
- height: '100%',
129
- overflow: 'auto',
130
- zIndex: '1',
131
- }}
132
137
  onclick={() => {
133
138
  props.collectionService.hasFocus.setValue(true)
134
139
  }}
135
140
  ariaMultiSelectable="true"
136
141
  >
137
- <table
138
- style={{ width: '100%', maxHeight: 'calc(100% - 4em)', position: 'relative', borderCollapse: 'collapse' }}
139
- >
142
+ <table>
140
143
  <thead>
141
144
  <tr>
142
145
  {props.columns.map((column) => {
143
146
  return (
144
- <th style={headerStyle}>
147
+ <th style={props.styles?.header}>
145
148
  {props.headerComponents?.[column]?.(column) || props.headerComponents?.default?.(column) || (
146
149
  <DataGridHeader<
147
150
  ReturnType<typeof props.collectionService.data.getValue>['entries'][number],
@@ -0,0 +1,344 @@
1
+ import type { FindOptions } from '@furystack/core'
2
+ import { Injector } from '@furystack/inject'
3
+ import { createComponent, initializeShadeRoot } from '@furystack/shades'
4
+ import { ObservableValue, sleepAsync } from '@furystack/utils'
5
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest'
6
+ import { CollectionService } from '../../services/collection-service.js'
7
+ import { DataGridFooter, dataGridItemsPerPage } from './footer.js'
8
+
9
+ type TestItem = { id: number; name: string }
10
+
11
+ describe('DataGridFooter', () => {
12
+ beforeEach(() => {
13
+ document.body.innerHTML = '<div id="root"></div>'
14
+ })
15
+
16
+ afterEach(() => {
17
+ document.body.innerHTML = ''
18
+ })
19
+
20
+ const createService = (entries: TestItem[] = [], count?: number) => {
21
+ const service = new CollectionService<TestItem>()
22
+ service.data.setValue({ entries, count: count ?? entries.length })
23
+ return service
24
+ }
25
+
26
+ const createFindOptions = (
27
+ top: number = 10,
28
+ skip: number = 0,
29
+ ): ObservableValue<FindOptions<TestItem, Array<keyof TestItem>>> => {
30
+ return new ObservableValue<FindOptions<TestItem, Array<keyof TestItem>>>({ top, skip })
31
+ }
32
+
33
+ it('should render with custom element', async () => {
34
+ const injector = new Injector()
35
+ const rootElement = document.getElementById('root') as HTMLDivElement
36
+ const service = createService()
37
+ const findOptions = createFindOptions()
38
+
39
+ initializeShadeRoot({
40
+ injector,
41
+ rootElement,
42
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
43
+ })
44
+
45
+ await sleepAsync(50)
46
+
47
+ const footer = document.querySelector('shade-data-grid-footer')
48
+ expect(footer).not.toBeNull()
49
+ })
50
+
51
+ it('should render items per page select', async () => {
52
+ const injector = new Injector()
53
+ const rootElement = document.getElementById('root') as HTMLDivElement
54
+ const service = createService()
55
+ const findOptions = createFindOptions()
56
+
57
+ initializeShadeRoot({
58
+ injector,
59
+ rootElement,
60
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
61
+ })
62
+
63
+ await sleepAsync(50)
64
+
65
+ const footer = document.querySelector('shade-data-grid-footer')
66
+ const selects = footer?.querySelectorAll('select')
67
+
68
+ expect(selects?.length).toBeGreaterThan(0)
69
+ })
70
+
71
+ it('should render all items per page options', async () => {
72
+ const injector = new Injector()
73
+ const rootElement = document.getElementById('root') as HTMLDivElement
74
+ const service = createService()
75
+ const findOptions = createFindOptions()
76
+
77
+ initializeShadeRoot({
78
+ injector,
79
+ rootElement,
80
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
81
+ })
82
+
83
+ await sleepAsync(50)
84
+
85
+ const footer = document.querySelector('shade-data-grid-footer')
86
+ const selects = Array.from(footer?.querySelectorAll('select') ?? [])
87
+ const itemsPerPageSelect = selects.find((s) => {
88
+ const parent = s.parentElement
89
+ return parent?.textContent?.includes('items per page')
90
+ })
91
+
92
+ expect(itemsPerPageSelect).toBeDefined()
93
+ const options = itemsPerPageSelect?.querySelectorAll('option')
94
+ expect(options?.length).toBe(dataGridItemsPerPage.length)
95
+ })
96
+
97
+ it('should show page selector when pagination is enabled', async () => {
98
+ const injector = new Injector()
99
+ const rootElement = document.getElementById('root') as HTMLDivElement
100
+ const service = createService([], 100)
101
+ const findOptions = createFindOptions(10, 0)
102
+
103
+ initializeShadeRoot({
104
+ injector,
105
+ rootElement,
106
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
107
+ })
108
+
109
+ await sleepAsync(50)
110
+
111
+ const footer = document.querySelector('shade-data-grid-footer')
112
+ const pager = footer?.querySelector('.pager')
113
+ expect(pager?.textContent).toContain('Goto page')
114
+ })
115
+
116
+ it('should hide page selector when showing all items (Infinity)', async () => {
117
+ const injector = new Injector()
118
+ const rootElement = document.getElementById('root') as HTMLDivElement
119
+ const service = createService([], 50)
120
+ const findOptions = createFindOptions(Infinity, 0)
121
+
122
+ initializeShadeRoot({
123
+ injector,
124
+ rootElement,
125
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
126
+ })
127
+
128
+ await sleepAsync(50)
129
+
130
+ const footer = document.querySelector('shade-data-grid-footer')
131
+ const pager = footer?.querySelector('.pager')
132
+ expect(pager?.textContent).not.toContain('Goto page')
133
+ })
134
+
135
+ it('should render correct number of page options based on data count and items per page', async () => {
136
+ const injector = new Injector()
137
+ const rootElement = document.getElementById('root') as HTMLDivElement
138
+ const service = createService([], 100)
139
+ const findOptions = createFindOptions(25, 0)
140
+
141
+ initializeShadeRoot({
142
+ injector,
143
+ rootElement,
144
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
145
+ })
146
+
147
+ await sleepAsync(50)
148
+
149
+ const footer = document.querySelector('shade-data-grid-footer')
150
+ const selects = Array.from(footer?.querySelectorAll('select') ?? [])
151
+ const pageSelect = selects.find((s) => {
152
+ const parent = s.parentElement
153
+ return parent?.textContent?.includes('Goto page')
154
+ })
155
+
156
+ expect(pageSelect).toBeDefined()
157
+ const options = pageSelect?.querySelectorAll('option')
158
+ expect(options?.length).toBe(4)
159
+ })
160
+
161
+ it('should update findOptions when page is changed', async () => {
162
+ const injector = new Injector()
163
+ const rootElement = document.getElementById('root') as HTMLDivElement
164
+ const service = createService([], 100)
165
+ const findOptions = createFindOptions(10, 0)
166
+
167
+ initializeShadeRoot({
168
+ injector,
169
+ rootElement,
170
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
171
+ })
172
+
173
+ await sleepAsync(50)
174
+
175
+ const footer = document.querySelector('shade-data-grid-footer')
176
+ const selects = Array.from(footer?.querySelectorAll('select') ?? [])
177
+ const pageSelect = selects.find((s) => {
178
+ const parent = s.parentElement
179
+ return parent?.textContent?.includes('Goto page')
180
+ })
181
+
182
+ expect(pageSelect).toBeDefined()
183
+
184
+ pageSelect!.value = '2'
185
+ pageSelect!.dispatchEvent(new Event('change', { bubbles: true }))
186
+
187
+ await sleepAsync(50)
188
+
189
+ const updatedOptions = findOptions.getValue()
190
+ expect(updatedOptions.skip).toBe(20)
191
+ })
192
+
193
+ it('should update findOptions when items per page is changed', async () => {
194
+ const injector = new Injector()
195
+ const rootElement = document.getElementById('root') as HTMLDivElement
196
+ const service = createService([], 100)
197
+ const findOptions = createFindOptions(10, 0)
198
+
199
+ initializeShadeRoot({
200
+ injector,
201
+ rootElement,
202
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
203
+ })
204
+
205
+ await sleepAsync(50)
206
+
207
+ const footer = document.querySelector('shade-data-grid-footer')
208
+ const selects = Array.from(footer?.querySelectorAll('select') ?? [])
209
+ const itemsPerPageSelect = selects.find((s) => {
210
+ const parent = s.parentElement
211
+ return parent?.textContent?.includes('items per page')
212
+ })
213
+
214
+ expect(itemsPerPageSelect).toBeDefined()
215
+
216
+ itemsPerPageSelect!.value = '25'
217
+ itemsPerPageSelect!.dispatchEvent(new Event('change', { bubbles: true }))
218
+
219
+ await sleepAsync(50)
220
+
221
+ const updatedOptions = findOptions.getValue()
222
+ expect(updatedOptions.top).toBe(25)
223
+ })
224
+
225
+ it('should preserve current page position when changing items per page', async () => {
226
+ const injector = new Injector()
227
+ const rootElement = document.getElementById('root') as HTMLDivElement
228
+ const service = createService([], 100)
229
+ const findOptions = createFindOptions(10, 20)
230
+
231
+ initializeShadeRoot({
232
+ injector,
233
+ rootElement,
234
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
235
+ })
236
+
237
+ await sleepAsync(50)
238
+
239
+ const footer = document.querySelector('shade-data-grid-footer')
240
+ const selects = Array.from(footer?.querySelectorAll('select') ?? [])
241
+ const itemsPerPageSelect = selects.find((s) => {
242
+ const parent = s.parentElement
243
+ return parent?.textContent?.includes('items per page')
244
+ })
245
+
246
+ expect(itemsPerPageSelect).toBeDefined()
247
+
248
+ itemsPerPageSelect!.value = '25'
249
+ itemsPerPageSelect!.dispatchEvent(new Event('change', { bubbles: true }))
250
+
251
+ await sleepAsync(50)
252
+
253
+ const updatedOptions = findOptions.getValue()
254
+ expect(updatedOptions.top).toBe(25)
255
+ expect(updatedOptions.skip).toBe(50)
256
+ })
257
+
258
+ it('should select the correct current page in the page selector', async () => {
259
+ const injector = new Injector()
260
+ const rootElement = document.getElementById('root') as HTMLDivElement
261
+ const service = createService([], 100)
262
+ const findOptions = createFindOptions(10, 30)
263
+
264
+ initializeShadeRoot({
265
+ injector,
266
+ rootElement,
267
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
268
+ })
269
+
270
+ await sleepAsync(50)
271
+
272
+ const footer = document.querySelector('shade-data-grid-footer')
273
+ const selects = Array.from(footer?.querySelectorAll('select') ?? [])
274
+ const pageSelect = selects.find((s) => {
275
+ const parent = s.parentElement
276
+ return parent?.textContent?.includes('Goto page')
277
+ })
278
+
279
+ expect(pageSelect).toBeDefined()
280
+ expect(pageSelect?.value).toBe('3')
281
+ })
282
+
283
+ it('should select the correct items per page option', async () => {
284
+ const injector = new Injector()
285
+ const rootElement = document.getElementById('root') as HTMLDivElement
286
+ const service = createService([], 100)
287
+ const findOptions = createFindOptions(25, 0)
288
+
289
+ initializeShadeRoot({
290
+ injector,
291
+ rootElement,
292
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
293
+ })
294
+
295
+ await sleepAsync(50)
296
+
297
+ const footer = document.querySelector('shade-data-grid-footer')
298
+ const selects = Array.from(footer?.querySelectorAll('select') ?? [])
299
+ const itemsPerPageSelect = selects.find((s) => {
300
+ const parent = s.parentElement
301
+ return parent?.textContent?.includes('items per page')
302
+ })
303
+
304
+ expect(itemsPerPageSelect).toBeDefined()
305
+ expect(itemsPerPageSelect?.value).toBe('25')
306
+ })
307
+
308
+ it('should react to data count changes', async () => {
309
+ const injector = new Injector()
310
+ const rootElement = document.getElementById('root') as HTMLDivElement
311
+ const service = createService([], 50)
312
+ const findOptions = createFindOptions(10, 0)
313
+
314
+ initializeShadeRoot({
315
+ injector,
316
+ rootElement,
317
+ jsxElement: <DataGridFooter service={service} findOptions={findOptions} />,
318
+ })
319
+
320
+ await sleepAsync(50)
321
+
322
+ let footer = document.querySelector('shade-data-grid-footer')
323
+ let selects = Array.from(footer?.querySelectorAll('select') ?? [])
324
+ let pageSelect = selects.find((s) => s.parentElement?.textContent?.includes('Goto page'))
325
+ let pageOptions = pageSelect?.querySelectorAll('option')
326
+
327
+ expect(pageOptions?.length).toBe(5)
328
+
329
+ service.data.setValue({ entries: [], count: 100 })
330
+
331
+ await sleepAsync(50)
332
+
333
+ footer = document.querySelector('shade-data-grid-footer')
334
+ selects = Array.from(footer?.querySelectorAll('select') ?? [])
335
+ pageSelect = selects.find((s) => s.parentElement?.textContent?.includes('Goto page'))
336
+ pageOptions = pageSelect?.querySelectorAll('option')
337
+
338
+ expect(pageOptions?.length).toBe(10)
339
+ })
340
+
341
+ it('should export dataGridItemsPerPage constant', () => {
342
+ expect(dataGridItemsPerPage).toEqual([10, 20, 25, 50, 100, Infinity])
343
+ })
344
+ })
@@ -2,7 +2,7 @@ import type { FindOptions } from '@furystack/core'
2
2
  import { Shade, createComponent } from '@furystack/shades'
3
3
  import type { ObservableValue } from '@furystack/utils'
4
4
  import type { CollectionService } from '../../services/collection-service.js'
5
- import { ThemeProviderService } from '../../services/theme-provider-service.js'
5
+ import { cssVariableTheme } from '../../services/css-variable-theme.js'
6
6
 
7
7
  export const dataGridItemsPerPage = [10, 20, 25, 50, 100, Infinity]
8
8
 
@@ -11,9 +11,23 @@ export const DataGridFooter: <T>(props: {
11
11
  findOptions: ObservableValue<FindOptions<T, Array<keyof T>>>
12
12
  }) => JSX.Element = Shade({
13
13
  shadowDomName: 'shade-data-grid-footer',
14
- render: ({ props, injector, useObservable }) => {
15
- const { theme } = injector.getInstance(ThemeProviderService)
16
-
14
+ css: {
15
+ display: 'block',
16
+ '& .pager': {
17
+ backdropFilter: 'blur(10px)',
18
+ color: cssVariableTheme.text.secondary,
19
+ position: 'sticky',
20
+ bottom: '0',
21
+ display: 'flex',
22
+ justifyContent: 'flex-end',
23
+ padding: '1em',
24
+ alignItems: 'center',
25
+ },
26
+ '& select': {
27
+ margin: '0 1em',
28
+ },
29
+ },
30
+ render: ({ props, useObservable }) => {
17
31
  const { service, findOptions } = props
18
32
  const [currentData] = useObservable('dataUpdater', service.data)
19
33
  const [currentOptions, setCurrentOptions] = useObservable('optionsUpdater', findOptions, {
@@ -32,24 +46,11 @@ export const DataGridFooter: <T>(props: {
32
46
  .map((_, index) => index)
33
47
 
34
48
  return (
35
- <div
36
- className="pager"
37
- style={{
38
- backdropFilter: 'blur(10px)',
39
- color: theme.text.secondary,
40
- position: 'sticky',
41
- bottom: '0',
42
- display: 'flex',
43
- justifyContent: 'flex-end',
44
- padding: '1em',
45
- alignItems: 'center',
46
- }}
47
- >
49
+ <div className="pager">
48
50
  {currentEntriesPerPage !== Infinity && (
49
51
  <div>
50
52
  Goto page
51
53
  <select
52
- style={{ margin: '0 1em' }}
53
54
  onchange={(ev) => {
54
55
  const value = parseInt((ev.target as HTMLInputElement).value, 10)
55
56
  setCurrentOptions({ ...currentOptions, skip: (currentOptions.top || 0) * value })
@@ -66,7 +67,6 @@ export const DataGridFooter: <T>(props: {
66
67
  <div>
67
68
  Show
68
69
  <select
69
- style={{ margin: '0 1em' }}
70
70
  onchange={(ev) => {
71
71
  const value = parseInt((ev.currentTarget as HTMLInputElement).value, 10)
72
72
  setCurrentOptions({