@kelpie/ui 0.8.0 → 0.10.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 (200) hide show
  1. package/dist/api/resource.d.ts +1 -1
  2. package/dist/api/resource.d.ts.map +1 -1
  3. package/dist/api/resource.js.map +1 -1
  4. package/dist/api/resources/consentPurposes.d.ts +13 -0
  5. package/dist/api/resources/consentPurposes.d.ts.map +1 -0
  6. package/dist/api/resources/consentPurposes.js +39 -0
  7. package/dist/api/resources/consentPurposes.js.map +1 -0
  8. package/dist/api/resources/customFields.d.ts +15 -0
  9. package/dist/api/resources/customFields.d.ts.map +1 -0
  10. package/dist/api/resources/customFields.js +41 -0
  11. package/dist/api/resources/customFields.js.map +1 -0
  12. package/dist/api/resources/enquiries.d.ts +39 -0
  13. package/dist/api/resources/enquiries.d.ts.map +1 -0
  14. package/dist/api/resources/enquiries.js +68 -0
  15. package/dist/api/resources/enquiries.js.map +1 -0
  16. package/dist/api/resources/forms.d.ts +21 -1
  17. package/dist/api/resources/forms.d.ts.map +1 -1
  18. package/dist/api/resources/forms.js +41 -0
  19. package/dist/api/resources/forms.js.map +1 -1
  20. package/dist/api/resources/importJobs.d.ts +5 -0
  21. package/dist/api/resources/importJobs.d.ts.map +1 -1
  22. package/dist/api/resources/importJobs.js +3 -0
  23. package/dist/api/resources/importJobs.js.map +1 -1
  24. package/dist/api/resources/opportunities.d.ts +2 -0
  25. package/dist/api/resources/opportunities.d.ts.map +1 -1
  26. package/dist/api/resources/opportunities.js +1 -0
  27. package/dist/api/resources/opportunities.js.map +1 -1
  28. package/dist/api/resources/sampleData.d.ts.map +1 -1
  29. package/dist/api/resources/sampleData.js +1 -0
  30. package/dist/api/resources/sampleData.js.map +1 -1
  31. package/dist/app/KelpieApp.d.ts.map +1 -1
  32. package/dist/app/KelpieApp.js +7 -1
  33. package/dist/app/KelpieApp.js.map +1 -1
  34. package/dist/components/ActivitiesPanel.d.ts.map +1 -1
  35. package/dist/components/ActivitiesPanel.js +1 -0
  36. package/dist/components/ActivitiesPanel.js.map +1 -1
  37. package/dist/components/CustomFieldsPanel.d.ts +23 -0
  38. package/dist/components/CustomFieldsPanel.d.ts.map +1 -0
  39. package/dist/components/CustomFieldsPanel.js +116 -0
  40. package/dist/components/CustomFieldsPanel.js.map +1 -0
  41. package/dist/components/FormsPanel.d.ts +18 -0
  42. package/dist/components/FormsPanel.d.ts.map +1 -0
  43. package/dist/components/FormsPanel.js +37 -0
  44. package/dist/components/FormsPanel.js.map +1 -0
  45. package/dist/components/PlanAttention.d.ts +3 -2
  46. package/dist/components/PlanAttention.d.ts.map +1 -1
  47. package/dist/components/PlanAttention.js +7 -3
  48. package/dist/components/PlanAttention.js.map +1 -1
  49. package/dist/components/Shell.d.ts.map +1 -1
  50. package/dist/components/Shell.js +3 -0
  51. package/dist/components/Shell.js.map +1 -1
  52. package/dist/components/useHasCustomFields.d.ts +13 -0
  53. package/dist/components/useHasCustomFields.d.ts.map +1 -0
  54. package/dist/components/useHasCustomFields.js +16 -0
  55. package/dist/components/useHasCustomFields.js.map +1 -0
  56. package/dist/pages/CompanyDetail.d.ts.map +1 -1
  57. package/dist/pages/CompanyDetail.js +24 -2
  58. package/dist/pages/CompanyDetail.js.map +1 -1
  59. package/dist/pages/DealDetail.d.ts.map +1 -1
  60. package/dist/pages/DealDetail.js +18 -1
  61. package/dist/pages/DealDetail.js.map +1 -1
  62. package/dist/pages/DecisionsPage.d.ts.map +1 -1
  63. package/dist/pages/DecisionsPage.js +2 -0
  64. package/dist/pages/DecisionsPage.js.map +1 -1
  65. package/dist/pages/EnquiriesPage.d.ts +2 -0
  66. package/dist/pages/EnquiriesPage.d.ts.map +1 -0
  67. package/dist/pages/EnquiriesPage.js +251 -0
  68. package/dist/pages/EnquiriesPage.js.map +1 -0
  69. package/dist/pages/EnquiryDetail.d.ts +2 -0
  70. package/dist/pages/EnquiryDetail.d.ts.map +1 -0
  71. package/dist/pages/EnquiryDetail.js +207 -0
  72. package/dist/pages/EnquiryDetail.js.map +1 -0
  73. package/dist/pages/EnquiryStageSettingsPage.d.ts +3 -0
  74. package/dist/pages/EnquiryStageSettingsPage.d.ts.map +1 -0
  75. package/dist/pages/EnquiryStageSettingsPage.js +34 -0
  76. package/dist/pages/EnquiryStageSettingsPage.js.map +1 -0
  77. package/dist/pages/FormDetail.d.ts.map +1 -1
  78. package/dist/pages/FormDetail.js +19 -1
  79. package/dist/pages/FormDetail.js.map +1 -1
  80. package/dist/pages/ListDetail.d.ts.map +1 -1
  81. package/dist/pages/ListDetail.js +27 -1
  82. package/dist/pages/ListDetail.js.map +1 -1
  83. package/dist/pages/OpportunityDetail.d.ts.map +1 -1
  84. package/dist/pages/OpportunityDetail.js +62 -3
  85. package/dist/pages/OpportunityDetail.js.map +1 -1
  86. package/dist/pages/PartnershipDetail.d.ts.map +1 -1
  87. package/dist/pages/PartnershipDetail.js +17 -1
  88. package/dist/pages/PartnershipDetail.js.map +1 -1
  89. package/dist/pages/PeoplePage.d.ts.map +1 -1
  90. package/dist/pages/PeoplePage.js +17 -0
  91. package/dist/pages/PeoplePage.js.map +1 -1
  92. package/dist/pages/PersonDetail.d.ts.map +1 -1
  93. package/dist/pages/PersonDetail.js +63 -3
  94. package/dist/pages/PersonDetail.js.map +1 -1
  95. package/dist/pages/PlanningPage.d.ts.map +1 -1
  96. package/dist/pages/PlanningPage.js +3 -0
  97. package/dist/pages/PlanningPage.js.map +1 -1
  98. package/dist/pages/RaiseDetail.d.ts.map +1 -1
  99. package/dist/pages/RaiseDetail.js +11 -1
  100. package/dist/pages/RaiseDetail.js.map +1 -1
  101. package/dist/pages/RoleDetail.js +1 -1
  102. package/dist/pages/RoleDetail.js.map +1 -1
  103. package/dist/pages/SearchPage.d.ts.map +1 -1
  104. package/dist/pages/SearchPage.js +1 -0
  105. package/dist/pages/SearchPage.js.map +1 -1
  106. package/dist/pages/admin/DataPage.d.ts.map +1 -1
  107. package/dist/pages/admin/DataPage.js +18 -3
  108. package/dist/pages/admin/DataPage.js.map +1 -1
  109. package/dist/pages/admin/FieldsPage.d.ts +2 -0
  110. package/dist/pages/admin/FieldsPage.d.ts.map +1 -0
  111. package/dist/pages/admin/FieldsPage.js +164 -0
  112. package/dist/pages/admin/FieldsPage.js.map +1 -0
  113. package/dist/pages/admin/PrivacyPage.d.ts +9 -0
  114. package/dist/pages/admin/PrivacyPage.d.ts.map +1 -0
  115. package/dist/pages/admin/PrivacyPage.js +170 -0
  116. package/dist/pages/admin/PrivacyPage.js.map +1 -0
  117. package/dist/pages/dashboard/attention.d.ts.map +1 -1
  118. package/dist/pages/dashboard/attention.js +3 -0
  119. package/dist/pages/dashboard/attention.js.map +1 -1
  120. package/dist/pages/forms/AddFieldMenu.d.ts +17 -0
  121. package/dist/pages/forms/AddFieldMenu.d.ts.map +1 -0
  122. package/dist/pages/forms/AddFieldMenu.js +43 -0
  123. package/dist/pages/forms/AddFieldMenu.js.map +1 -0
  124. package/dist/pages/forms/EmbedPanel.d.ts +4 -0
  125. package/dist/pages/forms/EmbedPanel.d.ts.map +1 -1
  126. package/dist/pages/forms/EmbedPanel.js +62 -3
  127. package/dist/pages/forms/EmbedPanel.js.map +1 -1
  128. package/dist/pages/forms/FieldsEditor.d.ts.map +1 -1
  129. package/dist/pages/forms/FieldsEditor.js +179 -36
  130. package/dist/pages/forms/FieldsEditor.js.map +1 -1
  131. package/dist/pages/forms/FormActions.d.ts +6 -0
  132. package/dist/pages/forms/FormActions.d.ts.map +1 -0
  133. package/dist/pages/forms/FormActions.js +149 -0
  134. package/dist/pages/forms/FormActions.js.map +1 -0
  135. package/dist/pages/forms/FormSettings.d.ts.map +1 -1
  136. package/dist/pages/forms/FormSettings.js +15 -19
  137. package/dist/pages/forms/FormSettings.js.map +1 -1
  138. package/dist/pages/forms/SubmissionDetail.d.ts +2 -0
  139. package/dist/pages/forms/SubmissionDetail.d.ts.map +1 -0
  140. package/dist/pages/forms/SubmissionDetail.js +76 -0
  141. package/dist/pages/forms/SubmissionDetail.js.map +1 -0
  142. package/dist/pages/forms/SubmissionsTable.d.ts.map +1 -1
  143. package/dist/pages/forms/SubmissionsTable.js +56 -8
  144. package/dist/pages/forms/SubmissionsTable.js.map +1 -1
  145. package/dist/pages/forms/fieldList.d.ts +11 -5
  146. package/dist/pages/forms/fieldList.d.ts.map +1 -1
  147. package/dist/pages/forms/fieldList.js +66 -6
  148. package/dist/pages/forms/fieldList.js.map +1 -1
  149. package/dist/pages/forms/template.d.ts +17 -0
  150. package/dist/pages/forms/template.d.ts.map +1 -1
  151. package/dist/pages/forms/template.js +93 -0
  152. package/dist/pages/forms/template.js.map +1 -1
  153. package/dist/pages/onboarding/WorkspaceStepPage.js +1 -1
  154. package/dist/pages/onboarding/WorkspaceStepPage.js.map +1 -1
  155. package/package.json +2 -2
  156. package/src/api/resource.ts +6 -1
  157. package/src/api/resources/consentPurposes.ts +83 -0
  158. package/src/api/resources/customFields.ts +88 -0
  159. package/src/api/resources/enquiries.ts +118 -0
  160. package/src/api/resources/forms.ts +58 -0
  161. package/src/api/resources/importJobs.ts +9 -0
  162. package/src/api/resources/opportunities.ts +3 -0
  163. package/src/api/resources/sampleData.ts +1 -0
  164. package/src/app/KelpieApp.tsx +12 -0
  165. package/src/components/ActivitiesPanel.tsx +1 -0
  166. package/src/components/CustomFieldsPanel.tsx +330 -0
  167. package/src/components/FormsPanel.tsx +86 -0
  168. package/src/components/PlanAttention.tsx +20 -3
  169. package/src/components/Shell.tsx +3 -0
  170. package/src/components/useHasCustomFields.ts +18 -0
  171. package/src/pages/CompanyDetail.tsx +36 -1
  172. package/src/pages/DealDetail.tsx +31 -0
  173. package/src/pages/DecisionsPage.tsx +2 -0
  174. package/src/pages/EnquiriesPage.tsx +434 -0
  175. package/src/pages/EnquiryDetail.tsx +554 -0
  176. package/src/pages/EnquiryStageSettingsPage.tsx +63 -0
  177. package/src/pages/FormDetail.tsx +23 -1
  178. package/src/pages/ListDetail.tsx +62 -0
  179. package/src/pages/OpportunityDetail.tsx +165 -2
  180. package/src/pages/PartnershipDetail.tsx +32 -0
  181. package/src/pages/PeoplePage.tsx +20 -0
  182. package/src/pages/PersonDetail.tsx +152 -3
  183. package/src/pages/PlanningPage.tsx +3 -0
  184. package/src/pages/RaiseDetail.tsx +21 -0
  185. package/src/pages/RoleDetail.tsx +1 -1
  186. package/src/pages/SearchPage.tsx +1 -0
  187. package/src/pages/admin/DataPage.tsx +51 -3
  188. package/src/pages/admin/FieldsPage.tsx +455 -0
  189. package/src/pages/admin/PrivacyPage.tsx +461 -0
  190. package/src/pages/dashboard/attention.ts +3 -0
  191. package/src/pages/forms/AddFieldMenu.tsx +121 -0
  192. package/src/pages/forms/EmbedPanel.tsx +163 -2
  193. package/src/pages/forms/FieldsEditor.tsx +539 -165
  194. package/src/pages/forms/FormActions.tsx +552 -0
  195. package/src/pages/forms/FormSettings.tsx +29 -70
  196. package/src/pages/forms/SubmissionDetail.tsx +249 -0
  197. package/src/pages/forms/SubmissionsTable.tsx +109 -16
  198. package/src/pages/forms/fieldList.ts +68 -5
  199. package/src/pages/forms/template.ts +103 -0
  200. package/src/pages/onboarding/WorkspaceStepPage.tsx +1 -1
@@ -1,4 +1,5 @@
1
1
  import type { Form } from '@kelpie/schemas'
2
+ import { useEffect, useId, useState } from 'react'
2
3
 
3
4
  import { useFormEmbed } from '../../api/resources/forms.ts'
4
5
  import { CopyButton } from '../../components/CopyButton.tsx'
@@ -12,14 +13,21 @@ import { SectionHeader } from '../../components/SectionHeader.tsx'
12
13
  * embed page is served by the service, so its address depends on where the
13
14
  * service is reached, which the server knows from the request and the browser
14
15
  * only happens to share while the two are same-origin.
16
+ *
17
+ * Each iframe snippet has a Preview that opens the bare embed document in a
18
+ * modal — fields only, the same document the snippet iframes — fixed height for
19
+ * the plain iframe, auto-resize for the script variant.
15
20
  */
16
21
 
17
22
  export interface EmbedPanelProps {
18
23
  readonly form: Form
19
24
  }
20
25
 
26
+ type PreviewMode = 'fixed' | 'resize'
27
+
21
28
  export function EmbedPanel({ form }: EmbedPanelProps): React.JSX.Element {
22
29
  const { snippets, isLoading, error } = useFormEmbed(form.id)
30
+ const [preview, setPreview] = useState<PreviewMode | null>(null)
23
31
 
24
32
  if (error !== null) {
25
33
  return <ErrorPanel error={error} />
@@ -33,7 +41,7 @@ export function EmbedPanel({ form }: EmbedPanelProps): React.JSX.Element {
33
41
  <div className="max-w-2xl space-y-5">
34
42
  <SectionHeader
35
43
  title="Embed"
36
- description="The page below is served by Kelpie, so a site embedding it loads nothing else."
44
+ description="Hosted page is the standalone URL with Kelpie chrome. The iframe snippets load a bare form fields only — so they sit inside your own site."
37
45
  />
38
46
 
39
47
  <div>
@@ -57,12 +65,31 @@ export function EmbedPanel({ form }: EmbedPanelProps): React.JSX.Element {
57
65
  label="iframe"
58
66
  hint="One tag, no JavaScript, fixed height."
59
67
  value={snippets.iframeSnippet}
68
+ onPreview={() => {
69
+ setPreview('fixed')
70
+ }}
60
71
  />
61
72
  <Snippet
62
73
  label="iframe with auto-resize"
63
74
  hint="Adds a listener that follows the page as fields appear and as the thank-you replaces the form."
64
75
  value={snippets.scriptSnippet}
76
+ onPreview={() => {
77
+ setPreview('resize')
78
+ }}
65
79
  />
80
+
81
+ {preview !== null && (
82
+ <EmbedPreviewModal
83
+ formId={form.id}
84
+ formName={form.name}
85
+ formTitle={form.title}
86
+ url={snippets.embedUrl}
87
+ mode={preview}
88
+ onClose={() => {
89
+ setPreview(null)
90
+ }}
91
+ />
92
+ )}
66
93
  </div>
67
94
  )
68
95
  }
@@ -71,16 +98,27 @@ function Snippet({
71
98
  label,
72
99
  hint,
73
100
  value,
101
+ onPreview,
74
102
  }: {
75
103
  readonly label: string
76
104
  readonly hint: string
77
105
  readonly value: string
106
+ readonly onPreview: () => void
78
107
  }): React.JSX.Element {
79
108
  return (
80
109
  <div>
81
110
  <div className="mb-1.5 flex items-center justify-between gap-2">
82
111
  <span className="text-[12px] font-medium text-ink">{label}</span>
83
- <CopyButton value={value} label={`Copy the ${label} snippet`} />
112
+ <div className="flex items-center gap-2">
113
+ <button
114
+ type="button"
115
+ onClick={onPreview}
116
+ className="rounded-md bg-accent px-3 py-1.5 text-[12px] font-semibold text-accent-fg transition hover:bg-accent-hover"
117
+ >
118
+ Preview
119
+ </button>
120
+ <CopyButton value={value} label={`Copy the ${label} snippet`} />
121
+ </div>
84
122
  </div>
85
123
  <textarea
86
124
  readOnly
@@ -93,3 +131,126 @@ function Snippet({
93
131
  </div>
94
132
  )
95
133
  }
134
+
135
+ /**
136
+ * Frames the hosted embed the way each snippet would: fixed 720px for the plain
137
+ * iframe, or listening for the height postMessage when previewing auto-resize.
138
+ */
139
+ function EmbedPreviewModal({
140
+ formId,
141
+ formName,
142
+ formTitle,
143
+ url,
144
+ mode,
145
+ onClose,
146
+ }: {
147
+ readonly formId: string
148
+ readonly formName: string
149
+ readonly formTitle: string
150
+ readonly url: string
151
+ readonly mode: PreviewMode
152
+ readonly onClose: () => void
153
+ }): React.JSX.Element {
154
+ const titleId = useId()
155
+ const heading = formTitle.trim().length > 0 ? formTitle : formName
156
+ const [height, setHeight] = useState(720)
157
+
158
+ useEffect(() => {
159
+ if (mode !== 'resize') {
160
+ return
161
+ }
162
+
163
+ function onMessage(event: MessageEvent): void {
164
+ const data = event.data as { kelpie?: string; formId?: string; height?: number } | null
165
+
166
+ if (
167
+ data === null ||
168
+ typeof data !== 'object' ||
169
+ data.kelpie !== 'height' ||
170
+ data.formId !== formId ||
171
+ typeof data.height !== 'number' ||
172
+ !Number.isFinite(data.height)
173
+ ) {
174
+ return
175
+ }
176
+
177
+ setHeight(Math.max(320, Math.ceil(data.height)))
178
+ }
179
+
180
+ window.addEventListener('message', onMessage)
181
+
182
+ return () => {
183
+ window.removeEventListener('message', onMessage)
184
+ }
185
+ }, [formId, mode])
186
+
187
+ useEffect(() => {
188
+ function onKeyDown(event: KeyboardEvent): void {
189
+ if (event.key === 'Escape') {
190
+ onClose()
191
+ }
192
+ }
193
+
194
+ window.addEventListener('keydown', onKeyDown)
195
+
196
+ return () => {
197
+ window.removeEventListener('keydown', onKeyDown)
198
+ }
199
+ }, [onClose])
200
+
201
+ return (
202
+ <div
203
+ className="fixed inset-0 z-50 flex items-end justify-center bg-ink/40 p-4 sm:items-center"
204
+ role="dialog"
205
+ aria-modal="true"
206
+ aria-labelledby={titleId}
207
+ onClick={onClose}
208
+ >
209
+ <div
210
+ className="animate-slide-in flex max-h-[90vh] w-full max-w-lg flex-col overflow-hidden rounded-md border border-border bg-surface-raised shadow-lg"
211
+ onClick={(event) => {
212
+ event.stopPropagation()
213
+ }}
214
+ >
215
+ <div className="flex shrink-0 items-start justify-between gap-3 border-b border-border px-4 py-3">
216
+ <div className="min-w-0">
217
+ <h2 id={titleId} className="truncate text-[14px] font-semibold text-ink">
218
+ Preview · {heading}
219
+ </h2>
220
+ <p className="mt-0.5 text-[11px] text-ink-faint">
221
+ {mode === 'resize'
222
+ ? 'Bare iframe embed with auto-resize — fields only, height follows the form.'
223
+ : 'Bare iframe embed — fields only, fixed height.'}
224
+ </p>
225
+ </div>
226
+ <button
227
+ type="button"
228
+ onClick={onClose}
229
+ className="shrink-0 rounded-md px-2 py-1 text-[12px] font-medium text-ink-muted transition hover:text-ink"
230
+ >
231
+ Close
232
+ </button>
233
+ </div>
234
+
235
+ <div className="min-h-0 flex-1 overflow-y-auto bg-[#f4f4f5] p-4">
236
+ <div className="overflow-hidden rounded-md border border-[#d4d4d8] bg-white shadow-sm">
237
+ <iframe
238
+ src={url}
239
+ title={`${heading} preview`}
240
+ style={{
241
+ width: '100%',
242
+ border: 0,
243
+ height: mode === 'fixed' ? '720px' : `${String(height)}px`,
244
+ colorScheme: 'normal',
245
+ }}
246
+ className="block bg-transparent"
247
+ />
248
+ </div>
249
+ <p className="mt-2 text-center text-[11px] text-ink-faint">
250
+ Simulated host page — the iframe uses its own neutral styles, not Kelpie&apos;s.
251
+ </p>
252
+ </div>
253
+ </div>
254
+ </div>
255
+ )
256
+ }