@pandacss/studio 0.0.0-dev-20230613163214

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 (250) hide show
  1. package/LICENSE.md +21 -0
  2. package/astro.config.ts +14 -0
  3. package/dist/studio.d.ts +13 -0
  4. package/dist/studio.js +2089 -0
  5. package/dist/studio.mjs +2087 -0
  6. package/index.ts +1 -0
  7. package/package.json +59 -0
  8. package/panda.config.ts +110 -0
  9. package/public/favicon.svg +13 -0
  10. package/src/components/analyzer/category-utilities.tsx +146 -0
  11. package/src/components/analyzer/data-combobox.tsx +125 -0
  12. package/src/components/analyzer/data-table.tsx +43 -0
  13. package/src/components/analyzer/external-icon.tsx +8 -0
  14. package/src/components/analyzer/file-details.tsx +101 -0
  15. package/src/components/analyzer/get-report-infos-from.ts +80 -0
  16. package/src/components/analyzer/quick-tooltip.tsx +15 -0
  17. package/src/components/analyzer/report-item-columns.tsx +52 -0
  18. package/src/components/analyzer/report-item-link.tsx +98 -0
  19. package/src/components/analyzer/section.tsx +24 -0
  20. package/src/components/analyzer/sort-icon.tsx +7 -0
  21. package/src/components/analyzer/text-with-count.tsx +28 -0
  22. package/src/components/analyzer/token-search-combobox.tsx +39 -0
  23. package/src/components/analyzer/truncated-text.tsx +26 -0
  24. package/src/components/analyzer/utility-details.tsx +312 -0
  25. package/src/components/color-constrast.tsx +131 -0
  26. package/src/components/color-item.tsx +37 -0
  27. package/src/components/color-wrapper.tsx +25 -0
  28. package/src/components/colors.tsx +96 -0
  29. package/src/components/empty-state.tsx +19 -0
  30. package/src/components/font-family.tsx +55 -0
  31. package/src/components/font-tokens.tsx +69 -0
  32. package/src/components/head.astro +35 -0
  33. package/src/components/icons.tsx +207 -0
  34. package/src/components/input.tsx +27 -0
  35. package/src/components/layer-styles.tsx +38 -0
  36. package/src/components/logo.tsx +34 -0
  37. package/src/components/nav-item.tsx +39 -0
  38. package/src/components/overview.tsx +65 -0
  39. package/src/components/radii.tsx +34 -0
  40. package/src/components/semantic-color.tsx +27 -0
  41. package/src/components/side-nav-item.astro +25 -0
  42. package/src/components/side-nav.astro +30 -0
  43. package/src/components/sizes.tsx +53 -0
  44. package/src/components/text-styles.tsx +33 -0
  45. package/src/components/theme-toggle.astro +56 -0
  46. package/src/components/token-analyzer.tsx +390 -0
  47. package/src/components/token-content.tsx +5 -0
  48. package/src/components/token-group.tsx +6 -0
  49. package/src/components/typography-playground.tsx +83 -0
  50. package/src/env.d.ts +1 -0
  51. package/src/icons/moon.tsx +15 -0
  52. package/src/icons/sun.tsx +19 -0
  53. package/src/layouts/Layout.astro +19 -0
  54. package/src/layouts/Sidebar.astro +35 -0
  55. package/src/lib/analysis-data.ts +17 -0
  56. package/src/lib/color-contrast-checker.ts +218 -0
  57. package/src/lib/color.ts +40 -0
  58. package/src/lib/constants.ts +140 -0
  59. package/src/lib/create-context.ts +27 -0
  60. package/src/lib/get-report-item.tsx +41 -0
  61. package/src/lib/group-in.ts +35 -0
  62. package/src/lib/panda.context.ts +23 -0
  63. package/src/lib/pick.ts +24 -0
  64. package/src/lib/sizes-sort.ts +10 -0
  65. package/src/lib/truncate.tsx +7 -0
  66. package/src/lib/use-color-docs.ts +101 -0
  67. package/src/pages/colors.astro +11 -0
  68. package/src/pages/font-sizes.astro +15 -0
  69. package/src/pages/font-weights.astro +15 -0
  70. package/src/pages/fonts.astro +11 -0
  71. package/src/pages/index.astro +8 -0
  72. package/src/pages/layer-styles.astro +11 -0
  73. package/src/pages/letter-spacings.astro +20 -0
  74. package/src/pages/line-heights.astro +21 -0
  75. package/src/pages/playground/contrast-checker.astro +11 -0
  76. package/src/pages/playground/typography.astro +11 -0
  77. package/src/pages/radii.astro +11 -0
  78. package/src/pages/sizes.astro +14 -0
  79. package/src/pages/spacing.astro +14 -0
  80. package/src/pages/text-styles.astro +11 -0
  81. package/src/pages/token-analyzer/file.astro +11 -0
  82. package/src/pages/token-analyzer/index.astro +11 -0
  83. package/src/pages/token-analyzer/utility.astro +11 -0
  84. package/styled-system/chunks/..__core____tests____composition.test.css +2 -0
  85. package/styled-system/chunks/src__components__analyzer__category-utilities.css +97 -0
  86. package/styled-system/chunks/src__components__analyzer__data-combobox.css +77 -0
  87. package/styled-system/chunks/src__components__analyzer__data-table.css +37 -0
  88. package/styled-system/chunks/src__components__analyzer__file-details.css +103 -0
  89. package/styled-system/chunks/src__components__analyzer__quick-tooltip.css +2 -0
  90. package/styled-system/chunks/src__components__analyzer__report-item-columns.css +29 -0
  91. package/styled-system/chunks/src__components__analyzer__report-item-link.css +109 -0
  92. package/styled-system/chunks/src__components__analyzer__section.css +29 -0
  93. package/styled-system/chunks/src__components__analyzer__text-with-count.css +33 -0
  94. package/styled-system/chunks/src__components__analyzer__truncated-text.css +13 -0
  95. package/styled-system/chunks/src__components__analyzer__utility-details.css +125 -0
  96. package/styled-system/chunks/src__components__color-constrast.css +114 -0
  97. package/styled-system/chunks/src__components__color-item.css +21 -0
  98. package/styled-system/chunks/src__components__color-wrapper.css +73 -0
  99. package/styled-system/chunks/src__components__colors.css +97 -0
  100. package/styled-system/chunks/src__components__empty-state.css +45 -0
  101. package/styled-system/chunks/src__components__font-family.css +85 -0
  102. package/styled-system/chunks/src__components__font-tokens.css +61 -0
  103. package/styled-system/chunks/src__components__input.css +68 -0
  104. package/styled-system/chunks/src__components__layer-styles.css +66 -0
  105. package/styled-system/chunks/src__components__nav-item.css +73 -0
  106. package/styled-system/chunks/src__components__overview.css +125 -0
  107. package/styled-system/chunks/src__components__radii.css +49 -0
  108. package/styled-system/chunks/src__components__semantic-color.css +45 -0
  109. package/styled-system/chunks/src__components__side-nav-item.css +33 -0
  110. package/styled-system/chunks/src__components__side-nav.css +49 -0
  111. package/styled-system/chunks/src__components__sizes.css +41 -0
  112. package/styled-system/chunks/src__components__text-styles.css +31 -0
  113. package/styled-system/chunks/src__components__theme-toggle.css +63 -0
  114. package/styled-system/chunks/src__components__token-analyzer.css +227 -0
  115. package/styled-system/chunks/src__components__token-content.css +13 -0
  116. package/styled-system/chunks/src__components__token-group.css +21 -0
  117. package/styled-system/chunks/src__components__token-search-combobox.css +2 -0
  118. package/styled-system/chunks/src__components__typography-playground.css +61 -0
  119. package/styled-system/chunks/src__layouts__Layout.css +2 -0
  120. package/styled-system/chunks/src__layouts__Sidebar.css +113 -0
  121. package/styled-system/chunks/src__pages__colors.css +2 -0
  122. package/styled-system/chunks/src__pages__font-sizes.css +2 -0
  123. package/styled-system/chunks/src__pages__font-weights.css +2 -0
  124. package/styled-system/chunks/src__pages__fonts.css +2 -0
  125. package/styled-system/chunks/src__pages__index.css +2 -0
  126. package/styled-system/chunks/src__pages__layer-styles.css +2 -0
  127. package/styled-system/chunks/src__pages__letter-spacings.css +2 -0
  128. package/styled-system/chunks/src__pages__line-heights.css +2 -0
  129. package/styled-system/chunks/src__pages__playground__contrast-checker.css +2 -0
  130. package/styled-system/chunks/src__pages__playground__typography.css +2 -0
  131. package/styled-system/chunks/src__pages__radii.css +2 -0
  132. package/styled-system/chunks/src__pages__sizes.css +2 -0
  133. package/styled-system/chunks/src__pages__spacing.css +2 -0
  134. package/styled-system/chunks/src__pages__text-styles.css +2 -0
  135. package/styled-system/chunks/src__pages__token-analyzer__file.css +2 -0
  136. package/styled-system/chunks/src__pages__token-analyzer__index.css +2 -0
  137. package/styled-system/chunks/src__pages__token-analyzer__utility.css +2 -0
  138. package/styled-system/css/conditions.mjs +147 -0
  139. package/styled-system/css/css.d.ts +2 -0
  140. package/styled-system/css/css.mjs +391 -0
  141. package/styled-system/css/cva.d.ts +5 -0
  142. package/styled-system/css/cva.mjs +63 -0
  143. package/styled-system/css/cx.d.ts +4 -0
  144. package/styled-system/css/cx.mjs +15 -0
  145. package/styled-system/css/index.d.ts +3 -0
  146. package/styled-system/css/index.mjs +3 -0
  147. package/styled-system/global.css +61 -0
  148. package/styled-system/helpers.mjs +251 -0
  149. package/styled-system/jsx/absolute-center.d.ts +8 -0
  150. package/styled-system/jsx/absolute-center.mjs +9 -0
  151. package/styled-system/jsx/aspect-ratio.d.ts +8 -0
  152. package/styled-system/jsx/aspect-ratio.mjs +9 -0
  153. package/styled-system/jsx/box.d.ts +8 -0
  154. package/styled-system/jsx/box.mjs +8 -0
  155. package/styled-system/jsx/center.d.ts +8 -0
  156. package/styled-system/jsx/center.mjs +9 -0
  157. package/styled-system/jsx/circle.d.ts +8 -0
  158. package/styled-system/jsx/circle.mjs +9 -0
  159. package/styled-system/jsx/container.d.ts +8 -0
  160. package/styled-system/jsx/container.mjs +8 -0
  161. package/styled-system/jsx/divider.d.ts +8 -0
  162. package/styled-system/jsx/divider.mjs +9 -0
  163. package/styled-system/jsx/factory.d.ts +2 -0
  164. package/styled-system/jsx/factory.mjs +59 -0
  165. package/styled-system/jsx/flex.d.ts +8 -0
  166. package/styled-system/jsx/flex.mjs +9 -0
  167. package/styled-system/jsx/float.d.ts +8 -0
  168. package/styled-system/jsx/float.mjs +9 -0
  169. package/styled-system/jsx/grid-item.d.ts +8 -0
  170. package/styled-system/jsx/grid-item.mjs +9 -0
  171. package/styled-system/jsx/grid.d.ts +8 -0
  172. package/styled-system/jsx/grid.mjs +9 -0
  173. package/styled-system/jsx/hstack.d.ts +8 -0
  174. package/styled-system/jsx/hstack.mjs +9 -0
  175. package/styled-system/jsx/index.d.ts +20 -0
  176. package/styled-system/jsx/index.mjs +19 -0
  177. package/styled-system/jsx/is-valid-prop.mjs +1010 -0
  178. package/styled-system/jsx/spacer.d.ts +8 -0
  179. package/styled-system/jsx/spacer.mjs +9 -0
  180. package/styled-system/jsx/square.d.ts +8 -0
  181. package/styled-system/jsx/square.mjs +9 -0
  182. package/styled-system/jsx/stack.d.ts +8 -0
  183. package/styled-system/jsx/stack.mjs +9 -0
  184. package/styled-system/jsx/styled-link.d.ts +8 -0
  185. package/styled-system/jsx/styled-link.mjs +8 -0
  186. package/styled-system/jsx/vstack.d.ts +8 -0
  187. package/styled-system/jsx/vstack.mjs +9 -0
  188. package/styled-system/jsx/wrap.d.ts +8 -0
  189. package/styled-system/jsx/wrap.mjs +9 -0
  190. package/styled-system/patterns/absolute-center.d.ts +14 -0
  191. package/styled-system/patterns/absolute-center.mjs +23 -0
  192. package/styled-system/patterns/aspect-ratio.d.ts +14 -0
  193. package/styled-system/patterns/aspect-ratio.mjs +25 -0
  194. package/styled-system/patterns/box.d.ts +14 -0
  195. package/styled-system/patterns/box.mjs +12 -0
  196. package/styled-system/patterns/center.d.ts +14 -0
  197. package/styled-system/patterns/center.mjs +18 -0
  198. package/styled-system/patterns/circle.d.ts +14 -0
  199. package/styled-system/patterns/circle.mjs +22 -0
  200. package/styled-system/patterns/container.d.ts +14 -0
  201. package/styled-system/patterns/container.mjs +18 -0
  202. package/styled-system/patterns/divider.d.ts +16 -0
  203. package/styled-system/patterns/divider.mjs +21 -0
  204. package/styled-system/patterns/flex.d.ts +20 -0
  205. package/styled-system/patterns/flex.mjs +23 -0
  206. package/styled-system/patterns/float.d.ts +17 -0
  207. package/styled-system/patterns/float.mjs +45 -0
  208. package/styled-system/patterns/grid-item.d.ts +19 -0
  209. package/styled-system/patterns/grid-item.mjs +20 -0
  210. package/styled-system/patterns/grid.d.ts +18 -0
  211. package/styled-system/patterns/grid.mjs +25 -0
  212. package/styled-system/patterns/hstack.d.ts +15 -0
  213. package/styled-system/patterns/hstack.mjs +20 -0
  214. package/styled-system/patterns/index.d.ts +18 -0
  215. package/styled-system/patterns/index.mjs +18 -0
  216. package/styled-system/patterns/spacer.d.ts +14 -0
  217. package/styled-system/patterns/spacer.mjs +18 -0
  218. package/styled-system/patterns/square.d.ts +14 -0
  219. package/styled-system/patterns/square.mjs +21 -0
  220. package/styled-system/patterns/stack.d.ts +17 -0
  221. package/styled-system/patterns/stack.mjs +20 -0
  222. package/styled-system/patterns/styled-link.d.ts +14 -0
  223. package/styled-system/patterns/styled-link.mjs +18 -0
  224. package/styled-system/patterns/vstack.d.ts +15 -0
  225. package/styled-system/patterns/vstack.mjs +20 -0
  226. package/styled-system/patterns/wrap.d.ts +18 -0
  227. package/styled-system/patterns/wrap.mjs +22 -0
  228. package/styled-system/reset.css +190 -0
  229. package/styled-system/static.css +5 -0
  230. package/styled-system/styles.css +938 -0
  231. package/styled-system/tokens/index.css +374 -0
  232. package/styled-system/tokens/index.d.ts +8 -0
  233. package/styled-system/tokens/index.mjs +1590 -0
  234. package/styled-system/tokens/keyframes.css +30 -0
  235. package/styled-system/tokens/tokens.d.ts +56 -0
  236. package/styled-system/types/composition.d.ts +110 -0
  237. package/styled-system/types/conditions.d.ts +135 -0
  238. package/styled-system/types/csstype.d.ts +20748 -0
  239. package/styled-system/types/global.d.ts +15 -0
  240. package/styled-system/types/helpers.d.ts +1 -0
  241. package/styled-system/types/index.d.ts +3 -0
  242. package/styled-system/types/jsx.d.ts +27 -0
  243. package/styled-system/types/parts.d.ts +5 -0
  244. package/styled-system/types/pattern.d.ts +52 -0
  245. package/styled-system/types/prop-type.d.ts +300 -0
  246. package/styled-system/types/recipe.d.ts +79 -0
  247. package/styled-system/types/selectors.d.ts +56 -0
  248. package/styled-system/types/style-props.d.ts +688 -0
  249. package/styled-system/types/system-types.d.ts +76 -0
  250. package/virtual-panda.ts +72 -0
@@ -0,0 +1,80 @@
1
+ import type { ReportItemJSON } from '@pandacss/types'
2
+ import { analysisData } from '../../lib/analysis-data'
3
+ import { getReportItem, type SearchableReportItemAttributes } from '../../lib/get-report-item'
4
+
5
+ export const getReportInfosFrom = (params: SearchableReportItemAttributes) => {
6
+ let byTokenName: Array<ReportItemJSON['id']> = []
7
+ let byCategory: Array<ReportItemJSON['id']> = []
8
+ let byPropName: Array<ReportItemJSON['id']> = []
9
+ let byInstanceName: Array<ReportItemJSON['id']> = []
10
+ let byFilepath: Array<ReportItemJSON['id']> = []
11
+ let hasParam = false
12
+
13
+ if (params.value) {
14
+ byTokenName =
15
+ analysisData.details.globalMaps.byTokenName[
16
+ params.value as keyof typeof analysisData.details.globalMaps.byTokenName
17
+ ] ?? []
18
+ hasParam = true
19
+ }
20
+
21
+ if (params.category) {
22
+ byCategory =
23
+ analysisData.details.globalMaps.byCategory[
24
+ params.category as keyof typeof analysisData.details.globalMaps.byCategory
25
+ ] ?? []
26
+ hasParam = true
27
+ }
28
+
29
+ if (params.propName) {
30
+ byPropName =
31
+ analysisData.details.globalMaps.byPropertyName[
32
+ params.propName as keyof typeof analysisData.details.globalMaps.byPropertyName
33
+ ] ?? []
34
+ hasParam = true
35
+ }
36
+
37
+ if (params.from) {
38
+ byInstanceName =
39
+ analysisData.details.globalMaps.byInstanceName[
40
+ params.from as keyof typeof analysisData.details.globalMaps.byInstanceName
41
+ ] ?? []
42
+ hasParam = true
43
+ }
44
+
45
+ if (params.filepath) {
46
+ byFilepath = analysisData.details.byFilepath[params.filepath as keyof typeof analysisData.details.byFilepath] ?? []
47
+ hasParam = true
48
+ }
49
+
50
+ return {
51
+ params,
52
+ hasParam,
53
+ byTokenName: byTokenName.map(getReportItem),
54
+ byCategory: byCategory.map(getReportItem),
55
+ byPropName: byPropName.map(getReportItem),
56
+ byInstanceName: byInstanceName.map(getReportItem),
57
+ byFilepath: byFilepath.map(getReportItem),
58
+ reportItemList: combineIntersections(byTokenName, byCategory, byPropName, byInstanceName, byFilepath).map(
59
+ getReportItem,
60
+ ),
61
+ }
62
+ }
63
+ function combineIntersections<T>(...lists: Array<T[]>) {
64
+ return lists.reduce((acc, current) => {
65
+ if (!acc.length) return current
66
+
67
+ if (!current.length) return acc
68
+
69
+ return intersection(acc, current)
70
+ }, [] as T[])
71
+ }
72
+ function intersection<T = any>(left: Array<T>, right: Array<T>) {
73
+ const _intersection = new Set()
74
+ for (const elem of right) {
75
+ if (left.includes(elem)) {
76
+ _intersection.add(elem)
77
+ }
78
+ }
79
+ return Array.from(_intersection) as Array<T>
80
+ }
@@ -0,0 +1,15 @@
1
+ import { Portal, Tooltip, TooltipContent, TooltipPositioner, TooltipTrigger } from '@ark-ui/react'
2
+ import type { ReactElement, ReactNode } from 'react'
3
+
4
+ export const QuickTooltip = ({ children, tooltip }: { children: ReactElement; tooltip: ReactNode }) => {
5
+ return (
6
+ <Tooltip openDelay={0} closeDelay={100} positioning={{ placement: 'bottom-start', gutter: 20 }}>
7
+ <TooltipTrigger>{children}</TooltipTrigger>
8
+ <Portal>
9
+ <TooltipPositioner>
10
+ <TooltipContent>{tooltip}</TooltipContent>
11
+ </TooltipPositioner>
12
+ </Portal>
13
+ </Tooltip>
14
+ )
15
+ }
@@ -0,0 +1,52 @@
1
+ import type { ReportItemJSON } from '@pandacss/types'
2
+ import { panda } from '../../../styled-system/jsx'
3
+ import { ReportItemOpenInEditorLink, UtilityLink } from './report-item-link'
4
+ import { QuickTooltip } from './quick-tooltip'
5
+
6
+ export const reportItemColumns = [
7
+ {
8
+ header: '#',
9
+ accessor: 'id',
10
+ cell: (item: ReportItemJSON) => <panda.span onClick={() => console.log(item)}>{item.id}</panda.span>,
11
+ },
12
+ { header: 'from', accessor: 'from', cell: (item: ReportItemJSON) => <UtilityLink from={item.from} /> },
13
+ {
14
+ header: 'category',
15
+ accessor: 'category',
16
+ cell: (item: ReportItemJSON) => <UtilityLink category={item.category} />,
17
+ },
18
+ {
19
+ header: 'property name',
20
+ accessor: 'propName',
21
+ cell: (item: ReportItemJSON) => <UtilityLink propName={item.propName} />,
22
+ },
23
+ {
24
+ header: 'token name',
25
+ accessor: 'value',
26
+ cell: (item: ReportItemJSON) => {
27
+ return (
28
+ <panda.div display="flex" alignItems="center">
29
+ {!item.isKnown && (
30
+ <QuickTooltip
31
+ tooltip={
32
+ <panda.span p="2" bgColor="white" border="1px solid rgba(0, 0, 0, 0.1)">
33
+ unknown token
34
+ </panda.span>
35
+ }
36
+ >
37
+ <panda.span mr="2" userSelect="none">
38
+ {'❌'}
39
+ </panda.span>
40
+ </QuickTooltip>
41
+ )}
42
+ <UtilityLink value={item.value} />
43
+ </panda.div>
44
+ )
45
+ },
46
+ },
47
+ {
48
+ header: 'filepath',
49
+ accessor: 'filepath',
50
+ cell: (item: ReportItemJSON) => <ReportItemOpenInEditorLink withRange {...item} />,
51
+ },
52
+ ] as const // TODO satisifes Column[]
@@ -0,0 +1,98 @@
1
+ import type { ReportItemJSON } from '@pandacss/types'
2
+ import { panda } from '../../../styled-system/jsx'
3
+ import { styledLink } from '../../../styled-system/patterns'
4
+ import { analysisData } from '../../lib/analysis-data'
5
+ import {
6
+ getReportItem,
7
+ getUtilityLink,
8
+ getReportRange,
9
+ getReportRelativeFilePath,
10
+ openReportItemInEditor,
11
+ type SearchableReportItemAttributes,
12
+ } from '../../lib/get-report-item'
13
+ import { ExternalIcon } from './external-icon'
14
+ import { QuickTooltip } from './quick-tooltip'
15
+ import { TextWithCount } from './text-with-count'
16
+ import { TruncatedText } from './truncated-text'
17
+
18
+ export const ReportItemLink = (reportItem: Partial<ReportItemJSON>) => {
19
+ const value = String(reportItem.value)
20
+ const withTokenName = analysisData.details.globalMaps.byTokenName[value] ?? []
21
+ const count = withTokenName?.filter((id) => getReportItem(id)?.propName === reportItem.propName)?.length
22
+
23
+ return (
24
+ <panda.a className={styledLink({})} href={getUtilityLink(reportItem)}>
25
+ <TextWithCount count={count}>
26
+ {reportItem.propName}.<TruncatedText text={value} />
27
+ </TextWithCount>
28
+ </panda.a>
29
+ )
30
+ }
31
+
32
+ const mapsByReportItemAttribute = {
33
+ propName: analysisData.details.globalMaps.byPropertyName,
34
+ value: analysisData.details.globalMaps.byTokenName,
35
+ category: analysisData.details.globalMaps.byCategory,
36
+ from: analysisData.details.globalMaps.byInstanceName,
37
+ filepath: analysisData.details.byFilepath,
38
+ }
39
+
40
+ /** Takes a single search param */
41
+ export const UtilityLink = (search: SearchableReportItemAttributes) => {
42
+ const value = search.value ?? search.propName ?? search.category ?? search.filepath ?? search.from
43
+
44
+ let list: number[] | undefined
45
+ if (search.value) {
46
+ list = mapsByReportItemAttribute.value[String(search.value)]
47
+ } else if (search.propName) {
48
+ list = mapsByReportItemAttribute.propName[search.propName]
49
+ } else if (search.category) {
50
+ list = mapsByReportItemAttribute.category[search.category]
51
+ } else if (search.filepath) {
52
+ list = mapsByReportItemAttribute.filepath[search.filepath]
53
+ } else if (search.from) {
54
+ list = mapsByReportItemAttribute.from[search.from]
55
+ }
56
+
57
+ return (
58
+ <panda.a
59
+ className={styledLink({ color: String(value).endsWith('!') ? 'red.400' : undefined })}
60
+ href={getUtilityLink(search)}
61
+ >
62
+ <TextWithCount count={(list ?? []).length}>
63
+ <TruncatedText text={String(value)} />
64
+ </TextWithCount>
65
+ </panda.a>
66
+ )
67
+ }
68
+
69
+ export const ReportItemOpenInEditorLink = ({ withRange, ...reportItem }: ReportItemJSON & { withRange?: boolean }) => {
70
+ return (
71
+ <panda.div display="flex" alignItems="center">
72
+ <panda.a
73
+ className={styledLink({ alignSelf: 'flex-start', mr: '2' })}
74
+ href={getUtilityLink({ filepath: reportItem.filepath })}
75
+ >
76
+ {getReportRelativeFilePath(reportItem.filepath)}
77
+ {withRange ? getReportRange(reportItem) : ''}
78
+ </panda.a>
79
+ <QuickTooltip
80
+ tooltip={
81
+ <panda.span p="2" bgColor="white" border="1px solid rgba(0, 0, 0, 0.1)">
82
+ Click to open in editor
83
+ </panda.span>
84
+ }
85
+ >
86
+ <panda.div
87
+ pos="relative"
88
+ maxW="14px"
89
+ flexShrink={0}
90
+ cursor="pointer"
91
+ onClickCapture={() => openReportItemInEditor(reportItem)}
92
+ >
93
+ <ExternalIcon />
94
+ </panda.div>
95
+ </QuickTooltip>
96
+ </panda.div>
97
+ )
98
+ }
@@ -0,0 +1,24 @@
1
+ import type { PropsWithChildren, ReactNode } from 'react'
2
+ import { panda, Stack } from '../../../styled-system/jsx'
3
+ import type { JsxStyleProps } from '../../../styled-system/types'
4
+
5
+ export const Section = ({
6
+ title,
7
+ subTitle,
8
+ children,
9
+ ...props
10
+ }: PropsWithChildren<{ title: ReactNode; subTitle?: ReactNode } & JsxStyleProps>) => {
11
+ return (
12
+ <Stack p="4" gap="4" w="100%">
13
+ {title && (
14
+ <panda.div w="full" display="flex">
15
+ <panda.h3>{title}</panda.h3>
16
+ {subTitle}
17
+ </panda.div>
18
+ )}
19
+ <panda.div p="4" w="100%" rounded="md" {...props}>
20
+ {children}
21
+ </panda.div>
22
+ </Stack>
23
+ )
24
+ }
@@ -0,0 +1,7 @@
1
+ export const SortIcon = () => {
2
+ return (
3
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
4
+ <path d="M15.344 17.778a.75.75 0 0 0-.75-.75h-5.16a.75.75 0 0 0 0 1.5h5.16a.75.75 0 0 0 .75-.75zm2.206-4a.75.75 0 0 0-.75-.75H7.204a.75.75 0 0 0 0 1.5H16.8a.75.75 0 0 0 .75-.75zm2.45-4a.75.75 0 0 0-.75-.75H4.75a.75.75 0 0 0 0 1.5h14.5a.75.75 0 0 0 .75-.75zm2-4a.75.75 0 0 0-.75-.75H2.75a.75.75 0 0 0 0 1.5h18.5a.75.75 0 0 0 .75-.75z" />
5
+ </svg>
6
+ )
7
+ }
@@ -0,0 +1,28 @@
1
+ import type { PropsWithChildren } from 'react'
2
+ import { panda } from '../../../styled-system/jsx'
3
+ import type { JsxStyleProps } from '../../../styled-system/types'
4
+
5
+ export const TextWithCount = ({ children, count, ...props }: PropsWithChildren<{ count: number } & JsxStyleProps>) => {
6
+ return (
7
+ <panda.div display="inline-flex" alignItems="center" {...props}>
8
+ <panda.span>{children}</panda.span>
9
+ <Sup>({count})</Sup>
10
+ </panda.div>
11
+ )
12
+ }
13
+
14
+ const Sup = ({ children, className }: PropsWithChildren<{ className?: string }>) => {
15
+ return (
16
+ <panda.sup
17
+ fontSize="75%"
18
+ lineHeight={0}
19
+ position="relative"
20
+ top="-0.35em"
21
+ opacity="0.5"
22
+ ml="1"
23
+ className={className}
24
+ >
25
+ {children}
26
+ </panda.sup>
27
+ )
28
+ }
@@ -0,0 +1,39 @@
1
+ import { analysisData } from '../../lib/analysis-data'
2
+ import { getUtilityLink, getReportRelativeFilePath } from '../../lib/get-report-item'
3
+ import { DataCombobox, type DataComboboxProps } from './data-combobox'
4
+
5
+ const searchList = new Map<string, string>()
6
+ const tokenNames = Object.keys(analysisData.details.globalMaps.byTokenName)
7
+ const propertyNames = Object.keys(analysisData.details.globalMaps.byPropertyName)
8
+ const categories = Object.keys(analysisData.details.globalMaps.byCategory)
9
+ const filepaths = Object.keys(analysisData.details.byFilepath)
10
+ tokenNames.sort().forEach((key) => {
11
+ searchList.set(key, 'value')
12
+ })
13
+ propertyNames.sort().forEach((key) => {
14
+ searchList.set(key, 'propName')
15
+ })
16
+ categories.sort().forEach((key) => {
17
+ searchList.set(key, 'category')
18
+ })
19
+ filepaths.sort().forEach((key) => {
20
+ searchList.set(getReportRelativeFilePath(key), 'filepath')
21
+ })
22
+
23
+ export const TokenSearchCombobox = (props: Omit<DataComboboxProps, 'options' | 'onSelect'>) => {
24
+ return (
25
+ <DataCombobox
26
+ placeholder={`Search for a token name (${tokenNames.length}), property name (${propertyNames.length}), category (${categories.length}), file path (${filepaths.length})...`}
27
+ {...props}
28
+ options={Array.from(searchList.entries()).map(([key, value]) => ({ label: `[${value}]: ${key}`, value: key }))}
29
+ onSelect={(option) => {
30
+ if (!option.value) return
31
+
32
+ const type = searchList.get(option.value)
33
+ if (!type) return
34
+
35
+ window.location.href = getUtilityLink({ [type]: option.value })
36
+ }}
37
+ />
38
+ )
39
+ }
@@ -0,0 +1,26 @@
1
+ import { panda } from '../../../styled-system/jsx'
2
+ import type { JsxStyleProps } from '../../../styled-system/types'
3
+ import { truncate } from '../../lib/truncate'
4
+ import { QuickTooltip } from './quick-tooltip'
5
+
6
+ export const TruncatedText = ({
7
+ text,
8
+ characters = 24,
9
+ ...props
10
+ }: { text: string; characters?: number } & JsxStyleProps) => {
11
+ if (text.length > characters) {
12
+ return (
13
+ <QuickTooltip
14
+ tooltip={
15
+ <panda.span p="2" bgColor="white" border="1px solid rgba(0, 0, 0, 0.1)">
16
+ {truncate(text, 80)}
17
+ </panda.span>
18
+ }
19
+ >
20
+ <panda.span {...props}>{text.substring(0, characters) + '...'}</panda.span>
21
+ </QuickTooltip>
22
+ )
23
+ }
24
+
25
+ return text as unknown as JSX.Element
26
+ }
@@ -0,0 +1,312 @@
1
+ import {
2
+ Portal,
3
+ Select,
4
+ SelectContent,
5
+ SelectLabel,
6
+ SelectOption,
7
+ SelectPositioner,
8
+ SelectTrigger,
9
+ } from '@ark-ui/react'
10
+ import { useState } from 'react'
11
+
12
+ import { css, cx } from '../../../styled-system/css'
13
+ import { Wrap, panda } from '../../../styled-system/jsx'
14
+ import { styledLink } from '../../../styled-system/patterns'
15
+
16
+ import { analysisData } from '../../lib/analysis-data'
17
+ import { createContext } from '../../lib/create-context'
18
+ import { getFileLink, getReportRelativeFilePath, type SearchableReportItemAttributes } from '../../lib/get-report-item'
19
+ import { TokenSearchCombobox } from './token-search-combobox'
20
+ import { DataCombobox, type DataComboboxOption } from './data-combobox'
21
+ import { DataTable } from './data-table'
22
+ import { getReportInfosFrom } from './get-report-infos-from'
23
+ import { reportItemColumns } from './report-item-columns'
24
+ import { Section } from './section'
25
+ import { TextWithCount } from './text-with-count'
26
+
27
+ export const UtilityDetails = () => {
28
+ const search = new URLSearchParams(window.location.search)
29
+ const initialParams = Object.fromEntries(search.entries()) as SearchableReportItemAttributes
30
+ const [params, setParams] = useState(initialParams)
31
+ // console.log({ params, globalMaps: analysisData.details.globalMaps })
32
+
33
+ const infos = getReportInfosFrom(params)
34
+ // console.log(infos)
35
+
36
+ return (
37
+ <panda.div>
38
+ <panda.div display="flex">
39
+ <panda.a href="/token-analyzer">
40
+ <panda.span fontWeight="bold">{'<'} </panda.span>Back
41
+ </panda.a>
42
+ <panda.div ml="auto">
43
+ <TokenSearchCombobox placeholder="Global search" />
44
+ </panda.div>
45
+ </panda.div>
46
+ <panda.div p="4" mt="4">
47
+ <DetailsProvider value={[infos, setParams]}>
48
+ <UtilityFilters />
49
+ <hr />
50
+ {infos.reportItemList.length ? (
51
+ <UtilityDetailsContent />
52
+ ) : !infos.hasParam ? (
53
+ <panda.div display="flex" justifyContent="center" fontSize="xl" p="16" fontWeight="bold">
54
+ Use at least one filter
55
+ </panda.div>
56
+ ) : (
57
+ <panda.div display="flex" justifyContent="center" fontSize="xl" p="16" fontWeight="bold">
58
+ No results
59
+ </panda.div>
60
+ )}
61
+ </DetailsProvider>
62
+ </panda.div>
63
+ </panda.div>
64
+ )
65
+ }
66
+
67
+ type Infos = ReturnType<typeof getReportInfosFrom>
68
+ const [DetailsProvider, useDetails] = createContext<[Infos, React.Dispatch<React.SetStateAction<Infos['params']>>]>({
69
+ name: 'UtilityDetailsContext',
70
+ })
71
+
72
+ const updateSearchParam = (key: string, value: string | undefined) => {
73
+ const search = new URLSearchParams(window.location.search)
74
+ if (value === undefined) {
75
+ search.delete(key)
76
+ } else {
77
+ search.set(key, value)
78
+ }
79
+ window.history.pushState(Object.fromEntries(search.entries()), '', `${window.location.pathname}?${search.toString()}`)
80
+ }
81
+
82
+ const uniq = (arr: string[]) => Array.from(new Set(arr))
83
+ const toOption = (value: string | object) =>
84
+ (typeof value === 'string' ? { value, label: value } : value) as DataComboboxOption
85
+ const toFilepathOption = (filepath: string) => ({ value: filepath, label: getReportRelativeFilePath(filepath) })
86
+
87
+ const UtilityFilters = () => {
88
+ const [infos, setParams] = useDetails()
89
+ const [resetKey, setResetKey] = useState(0)
90
+
91
+ const allTokenNames = Object.keys(analysisData.details.globalMaps.byTokenName)
92
+ const filteredTokenNames = uniq(infos.reportItemList.map((item) => String(item.value)))
93
+ const tokenNames = filteredTokenNames.length > 0 ? filteredTokenNames : allTokenNames
94
+
95
+ const allCategories = Object.keys(analysisData.details.globalMaps.byCategory)
96
+ const filteredCategories = uniq(infos.reportItemList.map((item) => item.category))
97
+ const categories = filteredCategories.length > 0 ? filteredCategories : allCategories
98
+
99
+ const allPropertyNames = Object.keys(analysisData.details.globalMaps.byPropertyName)
100
+ const filteredPropertyNames = uniq(infos.reportItemList.map((item) => item.propName))
101
+ const propertyNames = filteredPropertyNames.length > 0 ? filteredPropertyNames : allPropertyNames
102
+
103
+ const allFrom = Object.keys(analysisData.details.globalMaps.byInstanceName)
104
+ const filteredFrom = uniq(infos.reportItemList.map((item) => item.from))
105
+ const from = filteredFrom.length > 0 ? filteredFrom : allFrom
106
+
107
+ const allFilepath = Object.keys(analysisData.details.byFilepath).map(toFilepathOption)
108
+ const filteredFilepath = uniq(infos.reportItemList.map((item) => item.filepath)).map(toFilepathOption)
109
+ const filepath = filteredFilepath.length > 0 ? filteredFilepath : allFilepath
110
+
111
+ return (
112
+ <panda.div mb="4">
113
+ <panda.h3>Filters</panda.h3>
114
+ <Wrap key={resetKey}>
115
+ <DataCombobox
116
+ label="Token name"
117
+ options={tokenNames.map(toOption)}
118
+ onSelect={(e) => {
119
+ updateSearchParam('value', e.value)
120
+ return setParams((params) => ({ ...params, ['value']: e.value }))
121
+ }}
122
+ defaultValue={String(infos.params.value ?? '')}
123
+ />
124
+ <DataCombobox
125
+ label="Property name"
126
+ options={propertyNames.map(toOption)}
127
+ onSelect={(e) => {
128
+ updateSearchParam('propName', e.value)
129
+ return setParams((params) => ({ ...params, ['propName']: e.value }))
130
+ }}
131
+ defaultValue={String(infos.params.propName ?? '')}
132
+ />
133
+ <DataCombobox
134
+ label="Category"
135
+ options={categories.map(toOption)}
136
+ onSelect={(e) => {
137
+ updateSearchParam('category', e.value)
138
+ return setParams((params) => ({ ...params, ['category']: e.value }))
139
+ }}
140
+ defaultValue={String(infos.params.category ?? '')}
141
+ />
142
+ <DataCombobox
143
+ label="Instance name (from)"
144
+ options={from.map(toOption)}
145
+ onSelect={(e) => {
146
+ updateSearchParam('from', e.value)
147
+ return setParams((params) => ({ ...params, ['from']: e.value }))
148
+ }}
149
+ defaultValue={String(infos.params.from ?? '')}
150
+ />
151
+ <DataCombobox
152
+ label="Filepath"
153
+ options={filepath.map(toOption)}
154
+ onSelect={(e) => {
155
+ updateSearchParam('filepath', e.value)
156
+ return setParams((params) => ({ ...params, ['filepath']: e.value }))
157
+ }}
158
+ defaultValue={String(infos.params.filepath ?? '')}
159
+ />
160
+ {infos.hasParam && (
161
+ <panda.span
162
+ display="block"
163
+ alignSelf="flex-end"
164
+ mt="2"
165
+ cursor="pointer"
166
+ userSelect="none"
167
+ fontSize="lg"
168
+ fontWeight="bold"
169
+ onClick={() => {
170
+ updateSearchParam('value', undefined)
171
+ updateSearchParam('category', undefined)
172
+ updateSearchParam('propName', undefined)
173
+ updateSearchParam('from', undefined)
174
+ updateSearchParam('filepath', undefined)
175
+ setParams({})
176
+ setResetKey((k) => k + 1)
177
+ }}
178
+ >
179
+ [X] Clear filters
180
+ </panda.span>
181
+ )}
182
+ </Wrap>
183
+ </panda.div>
184
+ )
185
+ }
186
+
187
+ const UtilityDetailsContent = () => {
188
+ const [infos] = useDetails()
189
+
190
+ return (
191
+ <>
192
+ <ReportItemMatchingFiltersTable {...infos} />
193
+ <UsedInFiles />
194
+ </>
195
+ )
196
+ }
197
+
198
+ const UsedInFiles = () => {
199
+ const [infos] = useDetails()
200
+ const files = uniq(infos.reportItemList.map((item) => item.filepath))
201
+
202
+ return (
203
+ <panda.div>
204
+ <panda.h3>
205
+ <TextWithCount count={files.length}>Used in files</TextWithCount>
206
+ </panda.h3>
207
+ <panda.div display="flex" flexDirection="column">
208
+ {files.map((filepath) => (
209
+ <panda.a
210
+ mt="1"
211
+ key={filepath}
212
+ className={styledLink({})}
213
+ href={getFileLink({ filepath })}
214
+ onClick={(e) => e.stopPropagation()}
215
+ >
216
+ <TextWithCount count={infos.reportItemList.filter((item) => item.filepath === filepath).length}>
217
+ {getReportRelativeFilePath(filepath)}
218
+ </TextWithCount>
219
+ </panda.a>
220
+ ))}
221
+ </panda.div>
222
+ </panda.div>
223
+ )
224
+ }
225
+
226
+ const selectOptionClass = css({ padding: '4px 8px', bg: 'white' })
227
+
228
+ const ReportItemMatchingFiltersTable = (infos: Infos) => {
229
+ const tokenName = infos.params.value
230
+ const defaultOption = { label: `matching search filters`, value: 'reportItemList' }
231
+ const columns = reportItemColumns.filter((col) => (infos.params as any)[col.accessor] === undefined)
232
+
233
+ return (
234
+ <>
235
+ <Select defaultValue={defaultOption}>
236
+ {({ selectedOption }) => {
237
+ const value = (selectedOption?.value ?? defaultOption.value) as keyof Omit<Infos, 'params' | 'hasParam'>
238
+ // console.log({ value, list: infos[value] })
239
+
240
+ return (
241
+ <Section
242
+ title={
243
+ <>
244
+ <SelectLabel>By </SelectLabel>
245
+ <SelectTrigger>
246
+ <button>{selectedOption?.label}</button>
247
+ </SelectTrigger>
248
+ </>
249
+ }
250
+ subTitle={
251
+ <panda.span fontSize="md" fontWeight="bold" ml="auto">
252
+ Found ({infos[value].length}) matches{' '}
253
+ </panda.span>
254
+ }
255
+ bg="gray.50"
256
+ >
257
+ <DataTable list={infos[value]} columns={columns} />
258
+ <>
259
+ <Portal>
260
+ <SelectPositioner>
261
+ <SelectContent className={cx(selectOptionClass, css({ listStyle: 'none' }))}>
262
+ <SelectOption
263
+ className={selectOptionClass}
264
+ value={defaultOption.value}
265
+ label={defaultOption.label}
266
+ />
267
+ {infos.params.value && (
268
+ <SelectOption
269
+ className={selectOptionClass}
270
+ label={`token name (${tokenName})`}
271
+ value="byTokenName"
272
+ />
273
+ )}
274
+ {infos.params.propName && (
275
+ <SelectOption
276
+ className={selectOptionClass}
277
+ value="byPropName"
278
+ label={`property name (${infos.params.propName})`}
279
+ />
280
+ )}
281
+ {infos.params.category && (
282
+ <SelectOption
283
+ className={selectOptionClass}
284
+ value="byCategory"
285
+ label={`category (${infos.params.category})`}
286
+ />
287
+ )}
288
+ {infos.params.from && (
289
+ <SelectOption
290
+ className={selectOptionClass}
291
+ value="byInstanceName"
292
+ label={`from (${infos.params.from})`}
293
+ />
294
+ )}
295
+ {infos.params.filepath && (
296
+ <SelectOption
297
+ className={selectOptionClass}
298
+ value="byFilepath"
299
+ label={`filepath (${getReportRelativeFilePath(infos.params.filepath)})`}
300
+ />
301
+ )}
302
+ </SelectContent>
303
+ </SelectPositioner>
304
+ </Portal>
305
+ </>
306
+ </Section>
307
+ )
308
+ }}
309
+ </Select>
310
+ </>
311
+ )
312
+ }