@brdgapp/ui 0.1.1 → 1.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 (123) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/README.md +39 -85
  3. package/components/action-menu.d.ts +65 -0
  4. package/components/action-menu.js +48 -0
  5. package/components/avatar.d.ts +50 -0
  6. package/components/avatar.js +91 -0
  7. package/components/badge.d.ts +12 -0
  8. package/components/badge.js +23 -0
  9. package/components/bottom-sheet.d.ts +17 -0
  10. package/components/bottom-sheet.js +12 -0
  11. package/components/brand-mark.d.ts +20 -0
  12. package/components/brand-mark.js +44 -0
  13. package/components/button-group.d.ts +25 -0
  14. package/components/button-group.js +53 -0
  15. package/components/button.d.ts +33 -0
  16. package/components/button.js +82 -0
  17. package/components/card.d.ts +78 -0
  18. package/components/card.js +75 -0
  19. package/components/checkbox.d.ts +22 -0
  20. package/components/checkbox.js +35 -0
  21. package/components/collapsible.d.ts +29 -0
  22. package/components/collapsible.js +38 -0
  23. package/components/column-filter-menu.d.ts +15 -0
  24. package/components/column-filter-menu.js +30 -0
  25. package/components/column-sort-button.d.ts +18 -0
  26. package/components/column-sort-button.js +14 -0
  27. package/components/confirm-dialog.d.ts +20 -0
  28. package/components/confirm-dialog.js +17 -0
  29. package/components/copy-field.d.ts +17 -0
  30. package/components/copy-field.js +36 -0
  31. package/components/data-state.d.ts +44 -0
  32. package/components/data-state.js +25 -0
  33. package/components/data-table.d.ts +65 -0
  34. package/components/data-table.js +84 -0
  35. package/components/dialog.d.ts +19 -0
  36. package/components/dialog.js +10 -0
  37. package/components/drawer.d.ts +21 -0
  38. package/components/drawer.js +17 -0
  39. package/components/expandable-bio.d.ts +8 -0
  40. package/components/expandable-bio.js +26 -0
  41. package/components/field.d.ts +29 -0
  42. package/components/field.js +27 -0
  43. package/components/filter-chip.d.ts +11 -0
  44. package/components/filter-chip.js +8 -0
  45. package/components/filter-pill.d.ts +34 -0
  46. package/components/filter-pill.js +35 -0
  47. package/components/hover-card.d.ts +21 -0
  48. package/components/hover-card.js +20 -0
  49. package/components/icon-button.d.ts +16 -0
  50. package/components/icon-button.js +32 -0
  51. package/components/illustration.d.ts +33 -0
  52. package/components/illustration.js +70 -0
  53. package/components/info-hint.d.ts +29 -0
  54. package/components/info-hint.js +42 -0
  55. package/components/input.d.ts +9 -0
  56. package/components/input.js +15 -0
  57. package/components/network-graph.d.ts +48 -0
  58. package/components/network-graph.js +37 -0
  59. package/components/page-banner.d.ts +20 -0
  60. package/components/page-banner.js +29 -0
  61. package/components/scene.d.ts +12 -0
  62. package/components/scene.js +7 -0
  63. package/components/search-input.d.ts +8 -0
  64. package/components/search-input.js +14 -0
  65. package/components/segmented-control.d.ts +18 -0
  66. package/components/segmented-control.js +14 -0
  67. package/components/skeleton.d.ts +12 -0
  68. package/components/skeleton.js +21 -0
  69. package/components/skip-link.d.ts +8 -0
  70. package/components/skip-link.js +7 -0
  71. package/components/stat-box.d.ts +23 -0
  72. package/components/stat-box.js +29 -0
  73. package/components/switch.d.ts +13 -0
  74. package/components/switch.js +8 -0
  75. package/components/tabs.d.ts +6 -0
  76. package/components/tabs.js +25 -0
  77. package/components/tag-input.d.ts +15 -0
  78. package/components/tag-input.js +40 -0
  79. package/components/tag.d.ts +27 -0
  80. package/components/tag.js +35 -0
  81. package/components/textarea.d.ts +12 -0
  82. package/components/textarea.js +78 -0
  83. package/components/theme-switch.d.ts +6 -0
  84. package/components/theme-switch.js +16 -0
  85. package/components/toast.d.ts +25 -0
  86. package/components/toast.js +44 -0
  87. package/hooks/use-is-mobile.d.ts +2 -0
  88. package/hooks/use-is-mobile.js +16 -0
  89. package/hooks/use-mock-query.d.ts +23 -0
  90. package/hooks/use-mock-query.js +36 -0
  91. package/hooks/use-theme.d.ts +11 -0
  92. package/hooks/use-theme.js +34 -0
  93. package/lib/demo-controls.d.ts +24 -0
  94. package/lib/demo-controls.js +24 -0
  95. package/lib/format.d.ts +17 -0
  96. package/lib/format.js +55 -0
  97. package/lib/layout.d.ts +19 -0
  98. package/lib/layout.js +24 -0
  99. package/lib/motion.d.ts +16 -0
  100. package/lib/motion.js +18 -0
  101. package/lib/theme.d.ts +21 -0
  102. package/lib/theme.js +63 -0
  103. package/lib/utils.d.ts +22 -0
  104. package/lib/utils.js +27 -0
  105. package/package.json +32 -16
  106. package/styles/globals.css +595 -0
  107. package/src/index.ts +0 -18
  108. package/src/network-people-helper/README.md +0 -130
  109. package/src/network-people-helper/api.ts +0 -174
  110. package/src/network-people-helper/contact-avatar.tsx +0 -63
  111. package/src/network-people-helper/domain.ts +0 -14
  112. package/src/network-people-helper/icons.tsx +0 -130
  113. package/src/network-people-helper/index.ts +0 -6
  114. package/src/network-people-helper/network-people-helper.tsx +0 -397
  115. package/src/network-people-helper/network-people-nudge.tsx +0 -98
  116. package/src/network-people-helper/open-helper.ts +0 -22
  117. package/src/network-people-helper/person-menu.tsx +0 -211
  118. package/src/network-people-helper/styles.css +0 -848
  119. package/src/network-people-helper/types.ts +0 -23
  120. package/src/network-people-helper/use-network-people-list.ts +0 -122
  121. package/src/network-people-helper/use-network-preview.ts +0 -43
  122. package/src/provider.tsx +0 -59
  123. package/src/styles.css +0 -1
@@ -1,23 +0,0 @@
1
- import type { ReactNode } from "react"
2
-
3
- export type NetworkContact = {
4
- id: string
5
- name: string
6
- email: string | null
7
- shareLink: string | null
8
- profilePicUrl: string | null
9
- position: string | null
10
- company: string | null
11
- username: string | null
12
- isMember: boolean
13
- }
14
-
15
- export type NetworkPersonAction = {
16
- id: string
17
- label: string
18
- description?: string
19
- icon?: ReactNode
20
- onSelect: (contact: NetworkContact) => void
21
- }
22
-
23
- export type HelperPlacement = "bottom-end" | "bottom-start" | "top-end" | "top-start"
@@ -1,122 +0,0 @@
1
- "use client"
2
-
3
- import { useCallback, useEffect, useRef, useState } from "react"
4
- import { fetchNetworkPage, PAGE_SIZE } from "./api"
5
- import { cleanDomain } from "./domain"
6
- import { useBridgeUI } from "../provider"
7
- import type { NetworkContact } from "./types"
8
-
9
- type Options = {
10
- domain: string
11
- enabled: boolean
12
- search: string
13
- previewContacts: NetworkContact[]
14
- totalCount: number
15
- }
16
-
17
- export function useNetworkPeopleList({
18
- domain,
19
- enabled,
20
- search,
21
- previewContacts,
22
- totalCount,
23
- }: Options) {
24
- const config = useBridgeUI()
25
- const cleaned = cleanDomain(domain)
26
- const searchTerm = search.trim()
27
- const previewKey = previewContacts.map((contact) => contact.id).join("\n")
28
- const [pages, setPages] = useState<NetworkContact[][]>([])
29
- const [hasNextPage, setHasNextPage] = useState(false)
30
- const [isLoading, setIsLoading] = useState(false)
31
- const [isFetchingNextPage, setIsFetchingNextPage] = useState(false)
32
- const [isError, setIsError] = useState(false)
33
- const requestRef = useRef(0)
34
- const pagesRef = useRef(pages)
35
- pagesRef.current = pages
36
- const previewRef = useRef(previewContacts)
37
- previewRef.current = previewContacts
38
-
39
- const load = useCallback(
40
- async (offset: number, append: boolean, requestId: number) => {
41
- if (!config || !cleaned) return
42
- if (append) setIsFetchingNextPage(true)
43
- else setIsLoading(true)
44
- try {
45
- const contacts = await fetchNetworkPage(config, cleaned, { offset, search: searchTerm })
46
- if (requestRef.current !== requestId) return
47
- const base = append ? pagesRef.current.reduce((total, page) => total + page.length, 0) : 0
48
- const nextPages = append ? [...pagesRef.current, contacts] : [contacts]
49
- pagesRef.current = nextPages
50
- setPages(nextPages)
51
- const loaded = base + contacts.length
52
- const reachedEnd = !searchTerm && totalCount > 0 && loaded >= totalCount
53
- setHasNextPage(!reachedEnd && contacts.length >= PAGE_SIZE)
54
- setIsError(false)
55
- } catch {
56
- if (requestRef.current !== requestId) return
57
- if (!append) {
58
- pagesRef.current = []
59
- setPages([])
60
- setIsError(true)
61
- }
62
- setHasNextPage(false)
63
- } finally {
64
- if (requestRef.current === requestId) {
65
- setIsLoading(false)
66
- setIsFetchingNextPage(false)
67
- }
68
- }
69
- },
70
- [config, cleaned, searchTerm, totalCount],
71
- )
72
-
73
- useEffect(() => {
74
- if (!enabled || !config || !cleaned) {
75
- pagesRef.current = []
76
- setPages([])
77
- setHasNextPage(false)
78
- setIsLoading(false)
79
- setIsFetchingNextPage(false)
80
- setIsError(false)
81
- return
82
- }
83
-
84
- const requestId = ++requestRef.current
85
- const seeded = !searchTerm ? previewRef.current : []
86
- if (seeded.length > 0) {
87
- pagesRef.current = [seeded]
88
- setPages([seeded])
89
- setIsError(false)
90
- setIsLoading(false)
91
- if (totalCount > 0 && seeded.length >= totalCount) {
92
- setHasNextPage(false)
93
- } else {
94
- setHasNextPage(true)
95
- void load(seeded.length, true, requestId)
96
- }
97
- } else {
98
- pagesRef.current = []
99
- setPages([])
100
- void load(0, false, requestId)
101
- }
102
-
103
- return () => {
104
- requestRef.current += 1
105
- }
106
- }, [enabled, config, cleaned, searchTerm, previewKey, totalCount, load])
107
-
108
- const fetchNextPage = useCallback(() => {
109
- if (!hasNextPage || isFetchingNextPage || isLoading) return
110
- const loaded = pagesRef.current.reduce((total, page) => total + page.length, 0)
111
- void load(loaded, true, requestRef.current)
112
- }, [hasNextPage, isFetchingNextPage, isLoading, load])
113
-
114
- return {
115
- people: pages.flat(),
116
- isLoading,
117
- isFetchingNextPage,
118
- hasNextPage,
119
- fetchNextPage,
120
- isError,
121
- }
122
- }
@@ -1,43 +0,0 @@
1
- "use client"
2
-
3
- import { useEffect, useState } from "react"
4
- import { fetchNetworkPreview } from "./api"
5
- import { cleanDomain } from "./domain"
6
- import { useBridgeUI } from "../provider"
7
- import type { NetworkContact } from "./types"
8
-
9
- export type NetworkPreviewState = {
10
- status: "idle" | "loading" | "ready" | "error"
11
- count: number
12
- contacts: NetworkContact[]
13
- }
14
-
15
- const IDLE: NetworkPreviewState = { status: "idle", count: 0, contacts: [] }
16
-
17
- export function useNetworkPreview(domain: string, enabled: boolean): NetworkPreviewState {
18
- const config = useBridgeUI()
19
- const cleaned = cleanDomain(domain)
20
- const [state, setState] = useState<NetworkPreviewState & { domain: string }>({
21
- ...IDLE,
22
- domain: cleaned,
23
- })
24
-
25
- useEffect(() => {
26
- if (!enabled || !config || !cleaned) return
27
- let cancelled = false
28
- setState({ status: "loading", count: 0, contacts: [], domain: cleaned })
29
- fetchNetworkPreview(config, cleaned)
30
- .then((data) => {
31
- if (!cancelled) setState({ status: "ready", domain: cleaned, ...data })
32
- })
33
- .catch(() => {
34
- if (!cancelled) setState({ status: "error", count: 0, contacts: [], domain: cleaned })
35
- })
36
- return () => {
37
- cancelled = true
38
- }
39
- }, [enabled, config, cleaned])
40
-
41
- if (state.domain !== cleaned) return IDLE
42
- return state
43
- }
package/src/provider.tsx DELETED
@@ -1,59 +0,0 @@
1
- "use client"
2
-
3
- import { createContext, useContext, useMemo, useRef, type ReactNode } from "react"
4
-
5
- export type BridgeClientConfig = {
6
- apiBaseUrl: string
7
- getAccessToken: () => Promise<string | null> | string | null
8
- introInboxUrl: string
9
- profileUrlForUsername: (username: string) => string
10
- }
11
-
12
- /** Production Bridge API, including the `/api/v4` prefix. */
13
- export const DEFAULT_API_BASE_URL = "https://api.brdg.app/api/v4"
14
-
15
- const DEFAULT_INTRO_INBOX_URL = "https://intros.brdg.app/inbox"
16
-
17
- function defaultProfileUrl(username: string): string {
18
- return `https://os.brdg.app/to/${encodeURIComponent(username.trim())}`
19
- }
20
-
21
- const BridgeUIContext = createContext<BridgeClientConfig | null>(null)
22
-
23
- export type BridgeUIProviderProps = {
24
- /** Override the production API (`https://api.brdg.app/api/v4`) for staging or local. */
25
- apiBaseUrl?: string
26
- getAccessToken: () => Promise<string | null> | string | null
27
- /** Inbox used by the built-in Make intro action. */
28
- introInboxUrl?: string
29
- /** Profile URL used by the built-in View Bridge profile action. */
30
- profileUrlForUsername?: (username: string) => string
31
- children: ReactNode
32
- }
33
-
34
- export function BridgeUIProvider({
35
- apiBaseUrl = DEFAULT_API_BASE_URL,
36
- getAccessToken,
37
- introInboxUrl = DEFAULT_INTRO_INBOX_URL,
38
- profileUrlForUsername = defaultProfileUrl,
39
- children,
40
- }: BridgeUIProviderProps) {
41
- const getAccessTokenRef = useRef(getAccessToken)
42
- getAccessTokenRef.current = getAccessToken
43
-
44
- const value = useMemo<BridgeClientConfig>(
45
- () => ({
46
- apiBaseUrl: apiBaseUrl.replace(/\/$/, ""),
47
- getAccessToken: () => getAccessTokenRef.current(),
48
- introInboxUrl,
49
- profileUrlForUsername,
50
- }),
51
- [apiBaseUrl, introInboxUrl, profileUrlForUsername],
52
- )
53
-
54
- return <BridgeUIContext.Provider value={value}>{children}</BridgeUIContext.Provider>
55
- }
56
-
57
- export function useBridgeUI(): BridgeClientConfig | null {
58
- return useContext(BridgeUIContext)
59
- }
package/src/styles.css DELETED
@@ -1 +0,0 @@
1
- @import "./network-people-helper/styles.css";