@mdxui/issues 6.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.
@@ -0,0 +1,260 @@
1
+ import { useCallback } from 'react'
2
+ import { useIssuesStore } from './use-issues-store'
3
+ import type { Issue, IssueStatus, IssuePriority } from '../types'
4
+
5
+ export interface IssueMutations {
6
+ /** Update issue title */
7
+ updateTitle: (id: string, title: string) => Promise<void>
8
+ /** Update issue status */
9
+ updateStatus: (id: string, status: IssueStatus) => Promise<void>
10
+ /** Update issue priority */
11
+ updatePriority: (id: string, priority: IssuePriority) => Promise<void>
12
+ /** Update issue assignee */
13
+ updateAssignee: (id: string, assignee: string | undefined) => Promise<void>
14
+ /** Add label to issue */
15
+ addLabel: (id: string, label: string) => Promise<void>
16
+ /** Remove label from issue */
17
+ removeLabel: (id: string, label: string) => Promise<void>
18
+ /** Update description */
19
+ updateDescription: (id: string, description: string) => Promise<void>
20
+ /** Update design notes */
21
+ updateDesign: (id: string, design: string) => Promise<void>
22
+ /** Update acceptance criteria */
23
+ updateAcceptance: (id: string, acceptance: string) => Promise<void>
24
+ /** Update notes */
25
+ updateNotes: (id: string, notes: string) => Promise<void>
26
+ /** Add dependency */
27
+ addDependency: (id: string, dependsOn: string) => Promise<void>
28
+ /** Remove dependency */
29
+ removeDependency: (id: string, dependsOn: string) => Promise<void>
30
+ /** Close issue */
31
+ closeIssue: (id: string, reason?: string) => Promise<void>
32
+ /** Reopen issue */
33
+ reopenIssue: (id: string) => Promise<void>
34
+ /** Create issue */
35
+ createIssue: (issue: Omit<Issue, 'id' | 'createdAt' | 'updatedAt'>) => Promise<Issue>
36
+ /** Delete issue */
37
+ deleteIssue: (id: string) => Promise<void>
38
+ }
39
+
40
+ export interface UseIssueMutationsOptions {
41
+ /** RPC transport function for beads CLI */
42
+ transport?: (method: string, params: Record<string, unknown>) => Promise<unknown>
43
+ /** On mutation success */
44
+ onSuccess?: (method: string, result: unknown) => void
45
+ /** On mutation error */
46
+ onError?: (method: string, error: Error) => void
47
+ }
48
+
49
+ export function useIssueMutations(options: UseIssueMutationsOptions = {}): IssueMutations {
50
+ const { transport, onSuccess, onError } = options
51
+ const updateIssue = useIssuesStore((s) => s.updateIssue)
52
+ const addIssue = useIssuesStore((s) => s.addIssue)
53
+ const removeIssue = useIssuesStore((s) => s.removeIssue)
54
+
55
+ const mutate = useCallback(
56
+ async (method: string, params: Record<string, unknown>) => {
57
+ try {
58
+ const result = transport ? await transport(method, params) : undefined
59
+ onSuccess?.(method, result)
60
+ return result
61
+ } catch (error) {
62
+ onError?.(method, error as Error)
63
+ throw error
64
+ }
65
+ },
66
+ [transport, onSuccess, onError]
67
+ )
68
+
69
+ const updateTitle = useCallback(
70
+ async (id: string, title: string) => {
71
+ updateIssue(id, { title })
72
+ await mutate('update', { id, title })
73
+ },
74
+ [updateIssue, mutate]
75
+ )
76
+
77
+ const updateStatus = useCallback(
78
+ async (id: string, status: IssueStatus) => {
79
+ const updates: Partial<Issue> = { status }
80
+ if (status === 'closed') {
81
+ updates.closedAt = new Date().toISOString()
82
+ } else {
83
+ updates.closedAt = undefined
84
+ }
85
+ updateIssue(id, updates)
86
+ await mutate('update', { id, status })
87
+ },
88
+ [updateIssue, mutate]
89
+ )
90
+
91
+ const updatePriority = useCallback(
92
+ async (id: string, priority: IssuePriority) => {
93
+ updateIssue(id, { priority })
94
+ await mutate('update', { id, priority })
95
+ },
96
+ [updateIssue, mutate]
97
+ )
98
+
99
+ const updateAssignee = useCallback(
100
+ async (id: string, assignee: string | undefined) => {
101
+ updateIssue(id, { assignee })
102
+ await mutate('update', { id, assignee: assignee ?? null })
103
+ },
104
+ [updateIssue, mutate]
105
+ )
106
+
107
+ const addLabel = useCallback(
108
+ async (id: string, label: string) => {
109
+ const issue = useIssuesStore.getState().issues.find((i) => i.id === id)
110
+ if (issue && !issue.labels.includes(label)) {
111
+ const labels = [...issue.labels, label]
112
+ updateIssue(id, { labels })
113
+ await mutate('label', { id, add: [label] })
114
+ }
115
+ },
116
+ [updateIssue, mutate]
117
+ )
118
+
119
+ const removeLabel = useCallback(
120
+ async (id: string, label: string) => {
121
+ const issue = useIssuesStore.getState().issues.find((i) => i.id === id)
122
+ if (issue) {
123
+ const labels = issue.labels.filter((l: string) => l !== label)
124
+ updateIssue(id, { labels })
125
+ await mutate('label', { id, remove: [label] })
126
+ }
127
+ },
128
+ [updateIssue, mutate]
129
+ )
130
+
131
+ const updateDescription = useCallback(
132
+ async (id: string, description: string) => {
133
+ updateIssue(id, { description })
134
+ await mutate('update', { id, description })
135
+ },
136
+ [updateIssue, mutate]
137
+ )
138
+
139
+ const updateDesign = useCallback(
140
+ async (id: string, design: string) => {
141
+ updateIssue(id, { design })
142
+ await mutate('update', { id, design })
143
+ },
144
+ [updateIssue, mutate]
145
+ )
146
+
147
+ const updateAcceptance = useCallback(
148
+ async (id: string, acceptance: string) => {
149
+ updateIssue(id, { acceptance })
150
+ await mutate('update', { id, acceptance })
151
+ },
152
+ [updateIssue, mutate]
153
+ )
154
+
155
+ const updateNotes = useCallback(
156
+ async (id: string, notes: string) => {
157
+ updateIssue(id, { notes })
158
+ await mutate('update', { id, notes })
159
+ },
160
+ [updateIssue, mutate]
161
+ )
162
+
163
+ const addDependency = useCallback(
164
+ async (id: string, dependsOn: string) => {
165
+ const issue = useIssuesStore.getState().issues.find((i) => i.id === id)
166
+ if (issue && !issue.dependencies.includes(dependsOn)) {
167
+ updateIssue(id, { dependencies: [...issue.dependencies, dependsOn] })
168
+ await mutate('dep', { id, add: dependsOn })
169
+ }
170
+ },
171
+ [updateIssue, mutate]
172
+ )
173
+
174
+ const removeDependency = useCallback(
175
+ async (id: string, dependsOn: string) => {
176
+ const issue = useIssuesStore.getState().issues.find((i) => i.id === id)
177
+ if (issue) {
178
+ updateIssue(id, { dependencies: issue.dependencies.filter((d: string) => d !== dependsOn) })
179
+ await mutate('dep', { id, remove: dependsOn })
180
+ }
181
+ },
182
+ [updateIssue, mutate]
183
+ )
184
+
185
+ const closeIssue = useCallback(
186
+ async (id: string, reason?: string) => {
187
+ updateIssue(id, {
188
+ status: 'closed',
189
+ closedAt: new Date().toISOString(),
190
+ closeReason: reason,
191
+ })
192
+ await mutate('close', { id, reason })
193
+ },
194
+ [updateIssue, mutate]
195
+ )
196
+
197
+ const reopenIssue = useCallback(
198
+ async (id: string) => {
199
+ updateIssue(id, {
200
+ status: 'open',
201
+ closedAt: undefined,
202
+ closeReason: undefined,
203
+ })
204
+ await mutate('reopen', { id })
205
+ },
206
+ [updateIssue, mutate]
207
+ )
208
+
209
+ const createIssue = useCallback(
210
+ async (data: Omit<Issue, 'id' | 'createdAt' | 'updatedAt'>) => {
211
+ const now = new Date().toISOString()
212
+ const tempId = `temp-${Date.now()}`
213
+ const issue: Issue = {
214
+ ...data,
215
+ id: tempId,
216
+ createdAt: now,
217
+ updatedAt: now,
218
+ }
219
+ addIssue(issue)
220
+
221
+ const result = (await mutate('create', data)) as { id: string } | undefined
222
+ if (result?.id && result.id !== tempId) {
223
+ // Update with real ID from server
224
+ removeIssue(tempId)
225
+ const realIssue = { ...issue, id: result.id }
226
+ addIssue(realIssue)
227
+ return realIssue
228
+ }
229
+ return issue
230
+ },
231
+ [addIssue, removeIssue, mutate]
232
+ )
233
+
234
+ const deleteIssue = useCallback(
235
+ async (id: string) => {
236
+ removeIssue(id)
237
+ await mutate('delete', { id })
238
+ },
239
+ [removeIssue, mutate]
240
+ )
241
+
242
+ return {
243
+ updateTitle,
244
+ updateStatus,
245
+ updatePriority,
246
+ updateAssignee,
247
+ addLabel,
248
+ removeLabel,
249
+ updateDescription,
250
+ updateDesign,
251
+ updateAcceptance,
252
+ updateNotes,
253
+ addDependency,
254
+ removeDependency,
255
+ closeIssue,
256
+ reopenIssue,
257
+ createIssue,
258
+ deleteIssue,
259
+ }
260
+ }
@@ -0,0 +1,210 @@
1
+ import { create } from 'zustand'
2
+ import type { Issue, IssueFilters, IssueSort, ClosedTimeRange } from '../types'
3
+
4
+ interface IssuesState {
5
+ /** All issues */
6
+ issues: Issue[]
7
+ /** Currently selected issue ID */
8
+ selectedId: string | null
9
+ /** Current filters */
10
+ filters: IssueFilters
11
+ /** Current sort */
12
+ sort: IssueSort
13
+ /** Closed column time filter */
14
+ closedTimeRange: ClosedTimeRange
15
+ /** Loading state */
16
+ isLoading: boolean
17
+ /** Error state */
18
+ error: string | null
19
+
20
+ // Actions
21
+ setIssues: (issues: Issue[]) => void
22
+ addIssue: (issue: Issue) => void
23
+ updateIssue: (id: string, updates: Partial<Issue>) => void
24
+ removeIssue: (id: string) => void
25
+ selectIssue: (id: string | null) => void
26
+ setFilters: (filters: IssueFilters) => void
27
+ setSort: (sort: IssueSort) => void
28
+ setClosedTimeRange: (range: ClosedTimeRange) => void
29
+ setLoading: (loading: boolean) => void
30
+ setError: (error: string | null) => void
31
+ }
32
+
33
+ export const useIssuesStore = create<IssuesState>((set) => ({
34
+ issues: [],
35
+ selectedId: null,
36
+ filters: {},
37
+ sort: { field: 'priority', direction: 'asc' },
38
+ closedTimeRange: 'last7days',
39
+ isLoading: false,
40
+ error: null,
41
+
42
+ setIssues: (issues) => set({ issues }),
43
+
44
+ addIssue: (issue) =>
45
+ set((state) => ({
46
+ issues: [...state.issues, issue],
47
+ })),
48
+
49
+ updateIssue: (id, updates) =>
50
+ set((state) => ({
51
+ issues: state.issues.map((issue) =>
52
+ issue.id === id ? { ...issue, ...updates, updatedAt: new Date().toISOString() } : issue
53
+ ),
54
+ })),
55
+
56
+ removeIssue: (id) =>
57
+ set((state) => ({
58
+ issues: state.issues.filter((issue) => issue.id !== id),
59
+ selectedId: state.selectedId === id ? null : state.selectedId,
60
+ })),
61
+
62
+ selectIssue: (id) => set({ selectedId: id }),
63
+
64
+ setFilters: (filters) => set({ filters }),
65
+
66
+ setSort: (sort) => set({ sort }),
67
+
68
+ setClosedTimeRange: (closedTimeRange) => set({ closedTimeRange }),
69
+
70
+ setLoading: (isLoading) => set({ isLoading }),
71
+
72
+ setError: (error) => set({ error }),
73
+ }))
74
+
75
+ // Selector helpers
76
+ export const useIssue = (id: string | null) => {
77
+ return useIssuesStore((state) => (id ? state.issues.find((i) => i.id === id) : undefined))
78
+ }
79
+
80
+ export const useSelectedIssue = () => {
81
+ return useIssuesStore((state) =>
82
+ state.selectedId ? state.issues.find((i) => i.id === state.selectedId) : undefined
83
+ )
84
+ }
85
+
86
+ export const useFilteredIssues = () => {
87
+ return useIssuesStore((state) => {
88
+ let filtered = [...state.issues]
89
+
90
+ const { filters, sort, closedTimeRange } = state
91
+
92
+ // Apply status filter
93
+ if (filters.status?.length) {
94
+ filtered = filtered.filter((i) => filters.status!.includes(i.status))
95
+ }
96
+
97
+ // Apply type filter
98
+ if (filters.type?.length) {
99
+ filtered = filtered.filter((i) => filters.type!.includes(i.type))
100
+ }
101
+
102
+ // Apply priority filter
103
+ if (filters.priority?.length) {
104
+ filtered = filtered.filter((i) => filters.priority!.includes(i.priority))
105
+ }
106
+
107
+ // Apply assignee filter
108
+ if (filters.assignee) {
109
+ filtered = filtered.filter((i) => i.assignee === filters.assignee)
110
+ }
111
+
112
+ // Apply labels filter
113
+ if (filters.labels?.length) {
114
+ filtered = filtered.filter((i) => filters.labels!.some((l: string) => i.labels.includes(l)))
115
+ }
116
+
117
+ // Apply epic filter
118
+ if (filters.epic) {
119
+ filtered = filtered.filter((i) => i.epic === filters.epic)
120
+ }
121
+
122
+ // Apply search filter
123
+ if (filters.search) {
124
+ const search = filters.search.toLowerCase()
125
+ filtered = filtered.filter(
126
+ (i) => i.id.toLowerCase().includes(search) || i.title.toLowerCase().includes(search)
127
+ )
128
+ }
129
+
130
+ // Apply blocked filter
131
+ if (filters.blocked) {
132
+ filtered = filtered.filter((i) => i.status === 'blocked')
133
+ }
134
+
135
+ // Apply ready filter (no dependencies in non-closed status)
136
+ if (filters.ready) {
137
+ filtered = filtered.filter(
138
+ (i) =>
139
+ i.status === 'open' &&
140
+ !i.dependencies.some((depId: string) => {
141
+ const dep = state.issues.find((d) => d.id === depId)
142
+ return dep && dep.status !== 'closed'
143
+ })
144
+ )
145
+ }
146
+
147
+ // Apply closed time range filter for closed issues
148
+ if (closedTimeRange !== 'all') {
149
+ const now = new Date()
150
+ const cutoff = new Date()
151
+
152
+ if (closedTimeRange === 'today') {
153
+ cutoff.setDate(now.getDate() - 1)
154
+ } else if (closedTimeRange === 'last3days') {
155
+ cutoff.setDate(now.getDate() - 3)
156
+ } else if (closedTimeRange === 'last7days') {
157
+ cutoff.setDate(now.getDate() - 7)
158
+ }
159
+
160
+ filtered = filtered.filter((i) => {
161
+ if (i.status === 'closed' && i.closedAt) {
162
+ return new Date(i.closedAt) >= cutoff
163
+ }
164
+ return true
165
+ })
166
+ }
167
+
168
+ // Apply sort
169
+ filtered.sort((a, b) => {
170
+ let aVal: string | number
171
+ let bVal: string | number
172
+
173
+ switch (sort.field) {
174
+ case 'priority':
175
+ aVal = a.priority
176
+ bVal = b.priority
177
+ break
178
+ case 'createdAt':
179
+ aVal = a.createdAt
180
+ bVal = b.createdAt
181
+ break
182
+ case 'updatedAt':
183
+ aVal = a.updatedAt
184
+ bVal = b.updatedAt
185
+ break
186
+ case 'closedAt':
187
+ aVal = a.closedAt ?? ''
188
+ bVal = b.closedAt ?? ''
189
+ break
190
+ case 'title':
191
+ aVal = a.title.toLowerCase()
192
+ bVal = b.title.toLowerCase()
193
+ break
194
+ case 'status':
195
+ aVal = a.status
196
+ bVal = b.status
197
+ break
198
+ default:
199
+ aVal = a.createdAt
200
+ bVal = b.createdAt
201
+ }
202
+
203
+ if (aVal < bVal) return sort.direction === 'asc' ? -1 : 1
204
+ if (aVal > bVal) return sort.direction === 'asc' ? 1 : -1
205
+ return 0
206
+ })
207
+
208
+ return filtered
209
+ })
210
+ }
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ // Types
2
+ export type {
3
+ Issue,
4
+ IssueStatus,
5
+ IssueType,
6
+ IssuePriority,
7
+ IssueComment,
8
+ Epic,
9
+ IssueFilters,
10
+ IssueSort,
11
+ BoardColumn,
12
+ ClosedTimeRange,
13
+ } from './types'
14
+ export { defaultBoardColumns } from './types'
15
+
16
+ // Hooks
17
+ export * from './hooks'
18
+
19
+ // Components
20
+ export * from './components'
@@ -0,0 +1,194 @@
1
+ import { z } from 'zod'
2
+
3
+ // =============================================================================
4
+ // Issue Status
5
+ // =============================================================================
6
+
7
+ export const IssueStatusSchema = z.enum([
8
+ 'open',
9
+ 'in_progress',
10
+ 'blocked',
11
+ 'closed',
12
+ ])
13
+ export type IssueStatus = z.infer<typeof IssueStatusSchema>
14
+
15
+ // =============================================================================
16
+ // Issue Type
17
+ // =============================================================================
18
+
19
+ export const IssueTypeSchema = z.enum([
20
+ 'task',
21
+ 'bug',
22
+ 'feature',
23
+ 'epic',
24
+ 'story',
25
+ 'chore',
26
+ ])
27
+ export type IssueType = z.infer<typeof IssueTypeSchema>
28
+
29
+ // =============================================================================
30
+ // Issue Priority (0-4, 0=critical, 4=backlog)
31
+ // =============================================================================
32
+
33
+ export const IssuePrioritySchema = z.number().min(0).max(4)
34
+ export type IssuePriority = z.infer<typeof IssuePrioritySchema>
35
+
36
+ // =============================================================================
37
+ // Issue - Core data type
38
+ // =============================================================================
39
+
40
+ export const IssueSchema = z.object({
41
+ /** Unique issue ID (e.g., "beads-001") */
42
+ id: z.string(),
43
+ /** Issue title */
44
+ title: z.string(),
45
+ /** Detailed description (markdown) */
46
+ description: z.string().optional(),
47
+ /** Issue type */
48
+ type: IssueTypeSchema,
49
+ /** Issue status */
50
+ status: IssueStatusSchema,
51
+ /** Priority (0=critical, 4=backlog) */
52
+ priority: IssuePrioritySchema,
53
+ /** Assignee username */
54
+ assignee: z.string().optional(),
55
+ /** Labels */
56
+ labels: z.array(z.string()).default([]),
57
+ /** Parent epic ID */
58
+ epic: z.string().optional(),
59
+ /** IDs this issue depends on */
60
+ dependencies: z.array(z.string()).default([]),
61
+ /** IDs that depend on this issue */
62
+ dependents: z.array(z.string()).default([]),
63
+ /** Design notes (markdown) */
64
+ design: z.string().optional(),
65
+ /** Acceptance criteria (markdown) */
66
+ acceptance: z.string().optional(),
67
+ /** General notes (markdown) */
68
+ notes: z.string().optional(),
69
+ /** Created timestamp */
70
+ createdAt: z.string(),
71
+ /** Updated timestamp */
72
+ updatedAt: z.string(),
73
+ /** Closed timestamp */
74
+ closedAt: z.string().optional(),
75
+ /** Close reason */
76
+ closeReason: z.string().optional(),
77
+ })
78
+
79
+ export type Issue = z.infer<typeof IssueSchema>
80
+
81
+ // =============================================================================
82
+ // Issue Comment
83
+ // =============================================================================
84
+
85
+ export const IssueCommentSchema = z.object({
86
+ /** Comment ID */
87
+ id: z.string(),
88
+ /** Comment author */
89
+ author: z.string(),
90
+ /** Comment content (markdown) */
91
+ content: z.string(),
92
+ /** Created timestamp */
93
+ createdAt: z.string(),
94
+ /** Updated timestamp */
95
+ updatedAt: z.string().optional(),
96
+ })
97
+
98
+ export type IssueComment = z.infer<typeof IssueCommentSchema>
99
+
100
+ // =============================================================================
101
+ // Epic - Grouping of issues
102
+ // =============================================================================
103
+
104
+ export const EpicSchema = z.object({
105
+ /** Epic ID */
106
+ id: z.string(),
107
+ /** Epic title */
108
+ title: z.string(),
109
+ /** Epic description */
110
+ description: z.string().optional(),
111
+ /** Child issue IDs */
112
+ issues: z.array(z.string()).default([]),
113
+ /** Progress (0-100) */
114
+ progress: z.number().min(0).max(100).default(0),
115
+ /** Created timestamp */
116
+ createdAt: z.string(),
117
+ /** Updated timestamp */
118
+ updatedAt: z.string(),
119
+ })
120
+
121
+ export type Epic = z.infer<typeof EpicSchema>
122
+
123
+ // =============================================================================
124
+ // Issue Filters
125
+ // =============================================================================
126
+
127
+ export const IssueFiltersSchema = z.object({
128
+ /** Status filter */
129
+ status: z.array(IssueStatusSchema).optional(),
130
+ /** Type filter */
131
+ type: z.array(IssueTypeSchema).optional(),
132
+ /** Priority filter */
133
+ priority: z.array(IssuePrioritySchema).optional(),
134
+ /** Assignee filter */
135
+ assignee: z.string().optional(),
136
+ /** Label filter */
137
+ labels: z.array(z.string()).optional(),
138
+ /** Epic filter */
139
+ epic: z.string().optional(),
140
+ /** Search text */
141
+ search: z.string().optional(),
142
+ /** Only show blocked issues */
143
+ blocked: z.boolean().optional(),
144
+ /** Only show ready issues (no blockers) */
145
+ ready: z.boolean().optional(),
146
+ })
147
+
148
+ export type IssueFilters = z.infer<typeof IssueFiltersSchema>
149
+
150
+ // =============================================================================
151
+ // Issue Sort
152
+ // =============================================================================
153
+
154
+ export const IssueSortSchema = z.object({
155
+ field: z.enum(['priority', 'createdAt', 'updatedAt', 'closedAt', 'title', 'status']),
156
+ direction: z.enum(['asc', 'desc']),
157
+ })
158
+
159
+ export type IssueSort = z.infer<typeof IssueSortSchema>
160
+
161
+ // =============================================================================
162
+ // Board Column Configuration
163
+ // =============================================================================
164
+
165
+ export const BoardColumnSchema = z.object({
166
+ /** Column ID */
167
+ id: z.string(),
168
+ /** Column title */
169
+ title: z.string(),
170
+ /** Status values for this column */
171
+ statuses: z.array(IssueStatusSchema),
172
+ /** Column color */
173
+ color: z.string().optional(),
174
+ })
175
+
176
+ export type BoardColumn = z.infer<typeof BoardColumnSchema>
177
+
178
+ // =============================================================================
179
+ // Default board columns (matches beads-ui)
180
+ // =============================================================================
181
+
182
+ export const defaultBoardColumns: BoardColumn[] = [
183
+ { id: 'blocked', title: 'Blocked', statuses: ['blocked'], color: 'red' },
184
+ { id: 'ready', title: 'Ready', statuses: ['open'], color: 'blue' },
185
+ { id: 'in_progress', title: 'In Progress', statuses: ['in_progress'], color: 'yellow' },
186
+ { id: 'closed', title: 'Closed', statuses: ['closed'], color: 'green' },
187
+ ]
188
+
189
+ // =============================================================================
190
+ // Closed Time Range Filter
191
+ // =============================================================================
192
+
193
+ export const ClosedTimeRangeSchema = z.enum(['today', 'last3days', 'last7days', 'all'])
194
+ export type ClosedTimeRange = z.infer<typeof ClosedTimeRangeSchema>
package/tsconfig.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "@mdxui/typescript-config/react-library.json",
3
+ "include": ["src"],
4
+ "exclude": ["dist", "build", "node_modules", "../primitives"]
5
+ }