@pilotiq/pilotiq 0.8.2 → 0.9.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 (60) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/CHANGELOG.md +165 -0
  3. package/dist/Resource.d.ts +39 -0
  4. package/dist/Resource.d.ts.map +1 -1
  5. package/dist/Resource.js +30 -0
  6. package/dist/Resource.js.map +1 -1
  7. package/dist/pageData/navigation.d.ts +17 -1
  8. package/dist/pageData/navigation.d.ts.map +1 -1
  9. package/dist/pageData/navigation.js +14 -0
  10. package/dist/pageData/navigation.js.map +1 -1
  11. package/dist/react/AppShell.d.ts +5 -0
  12. package/dist/react/AppShell.d.ts.map +1 -1
  13. package/dist/react/AppShell.js +1 -1
  14. package/dist/react/AppShell.js.map +1 -1
  15. package/dist/react/FormCollabBindingRegistry.d.ts +71 -1
  16. package/dist/react/FormCollabBindingRegistry.d.ts.map +1 -1
  17. package/dist/react/FormCollabBindingRegistry.js.map +1 -1
  18. package/dist/react/FormStateContext.d.ts +17 -0
  19. package/dist/react/FormStateContext.d.ts.map +1 -1
  20. package/dist/react/FormStateContext.js +44 -3
  21. package/dist/react/FormStateContext.js.map +1 -1
  22. package/dist/react/RecordWrapperGate.d.ts +19 -6
  23. package/dist/react/RecordWrapperGate.d.ts.map +1 -1
  24. package/dist/react/RecordWrapperGate.js +18 -8
  25. package/dist/react/RecordWrapperGate.js.map +1 -1
  26. package/dist/react/fields/MarkdownInput.d.ts.map +1 -1
  27. package/dist/react/fields/MarkdownInput.js +105 -3
  28. package/dist/react/fields/MarkdownInput.js.map +1 -1
  29. package/dist/react/fields/TextLikeInput.d.ts +10 -0
  30. package/dist/react/fields/TextLikeInput.d.ts.map +1 -1
  31. package/dist/react/fields/TextLikeInput.js +179 -0
  32. package/dist/react/fields/TextLikeInput.js.map +1 -1
  33. package/dist/react/fields/textDelta.d.ts +44 -0
  34. package/dist/react/fields/textDelta.d.ts.map +1 -0
  35. package/dist/react/fields/textDelta.js +80 -0
  36. package/dist/react/fields/textDelta.js.map +1 -0
  37. package/dist/react/index.d.ts +2 -2
  38. package/dist/react/index.d.ts.map +1 -1
  39. package/dist/react/index.js +1 -1
  40. package/dist/react/index.js.map +1 -1
  41. package/dist/react/parseRecordEditUrl.d.ts +33 -9
  42. package/dist/react/parseRecordEditUrl.d.ts.map +1 -1
  43. package/dist/react/parseRecordEditUrl.js +40 -2
  44. package/dist/react/parseRecordEditUrl.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/Resource.test.ts +44 -0
  47. package/src/Resource.ts +58 -0
  48. package/src/pageData/navigation.ts +32 -1
  49. package/src/pageData.test.ts +36 -0
  50. package/src/react/AppShell.tsx +6 -1
  51. package/src/react/FormCollabBindingRegistry.ts +63 -1
  52. package/src/react/FormStateContext.tsx +62 -3
  53. package/src/react/RecordWrapperGate.tsx +26 -8
  54. package/src/react/fields/MarkdownInput.tsx +100 -3
  55. package/src/react/fields/TextLikeInput.tsx +203 -1
  56. package/src/react/fields/textDelta.test.ts +141 -0
  57. package/src/react/fields/textDelta.ts +86 -0
  58. package/src/react/index.ts +9 -1
  59. package/src/react/parseRecordEditUrl.test.ts +48 -1
  60. package/src/react/parseRecordEditUrl.ts +52 -13
@@ -1,12 +1,13 @@
1
1
  /**
2
- * Parses a pilotiq URL into a record-edit identity, or returns `null`
3
- * for any URL that isn't a record-bound edit page.
2
+ * URL record-page identity parser. Used by `RecordWrapperGate` (and any
3
+ * plugin that wants to reason about record-bound URLs) to decide whether
4
+ * the current page is a record-edit or record-view route.
4
5
  *
5
6
  * A URL matches when:
6
7
  * 1. it starts with the panel's `basePath`
7
- * 2. after stripping the prefix it ends with `/edit`
8
+ * 2. after stripping the prefix it ends with `/edit` or `/view`
8
9
  * 3. there are at least three remaining segments (resource slug,
9
- * record id, `edit`)
10
+ * record id, terminal token)
10
11
  *
11
12
  * The `resourceSlug` is the slash-joined chain of every segment up to
12
13
  * the record id — this gives clustered resources (`${base}/blog/articles/123/edit`)
@@ -14,22 +15,40 @@
14
15
  * distinct slugs so two URLs that target different records always
15
16
  * produce different room names downstream.
16
17
  *
17
- * `/admin/articles/123/edit` → { resourceSlug: 'articles', recordId: '123' }
18
- * `/admin/blog/articles/123/edit` → { resourceSlug: 'blog/articles', recordId: '123' }
19
- * `/admin/articles/123/comments/456/edit` → { resourceSlug: 'articles/123/comments', recordId: '456' }
20
- * `/admin/articles/123/comments` null (no trailing /edit)
21
- * `/admin/articles/123/comments/create` → null (no record id)
18
+ * `/admin/articles/123/edit` → { slug: 'articles', id: '123', role: 'edit' }
19
+ * `/admin/articles/123/view` → { slug: 'articles', id: '123', role: 'view' }
20
+ * `/admin/blog/articles/123/edit` → { slug: 'blog/articles', id: '123', role: 'edit' }
21
+ * `/admin/articles/123/comments/456/edit` { slug: 'articles/123/comments', id: '456', role: 'edit' }
22
+ * `/admin/articles/123/comments` → null (no trailing /edit or /view)
23
+ * `/admin/articles/123/comments/create` → null (terminal token isn't edit|view)
22
24
  * `/site/articles/123/edit` → null (basePath mismatch when basePath='/admin')
23
25
  */
24
- export interface RecordEditIdentity {
26
+
27
+ /** Page roles `parseRecordPageUrl` recognizes. `'edit'` and `'view'`
28
+ * are the two record-scoped page roles where collab and other
29
+ * record-bound plugins want to mount their per-record wrapper. */
30
+ export type RecordPageRole = 'edit' | 'view'
31
+
32
+ export interface RecordPageIdentity {
25
33
  resourceSlug: string
26
34
  recordId: string
35
+ /** Which terminal URL segment matched — `'edit'` for the writable edit
36
+ * page, `'view'` for the read-only view page. Lets the gate decide per
37
+ * resource whether collab activates on this role (defaults to `'edit'`
38
+ * only; resources opt into `'view'` for presence-only experiences). */
39
+ role: RecordPageRole
27
40
  }
28
41
 
29
- export function parseRecordEditUrl(
42
+ const RECOGNIZED_ROLES: ReadonlyArray<RecordPageRole> = ['edit', 'view']
43
+
44
+ /**
45
+ * Parse a pilotiq URL into a `{ slug, id, role }` identity. Returns
46
+ * `null` for any URL that isn't a record-edit or record-view page.
47
+ */
48
+ export function parseRecordPageUrl(
30
49
  currentPath: string,
31
50
  basePath: string,
32
- ): RecordEditIdentity | null {
51
+ ): RecordPageIdentity | null {
33
52
  if (!currentPath) return null
34
53
  // Normalise — trailing slashes on the URL or trailing slashes on
35
54
  // basePath would otherwise reject perfectly valid matches.
@@ -42,7 +61,8 @@ export function parseRecordEditUrl(
42
61
  const parts = tail.split('/').filter(Boolean)
43
62
 
44
63
  if (parts.length < 3) return null
45
- if (parts[parts.length - 1] !== 'edit') return null
64
+ const terminal = parts[parts.length - 1]!
65
+ if (!RECOGNIZED_ROLES.includes(terminal as RecordPageRole)) return null
46
66
 
47
67
  const recordId = parts[parts.length - 2]!
48
68
  const slugParts = parts.slice(0, parts.length - 2)
@@ -51,5 +71,24 @@ export function parseRecordEditUrl(
51
71
  return {
52
72
  resourceSlug: slugParts.join('/'),
53
73
  recordId,
74
+ role: terminal as RecordPageRole,
54
75
  }
55
76
  }
77
+
78
+ /** Legacy alias: parse a URL into an edit-only identity. Returns `null`
79
+ * for view URLs (and any non-edit URL). Kept for back-compat with the
80
+ * pre-`parseRecordPageUrl` public API; new code should call
81
+ * `parseRecordPageUrl` and branch on `role`. */
82
+ export interface RecordEditIdentity {
83
+ resourceSlug: string
84
+ recordId: string
85
+ }
86
+
87
+ export function parseRecordEditUrl(
88
+ currentPath: string,
89
+ basePath: string,
90
+ ): RecordEditIdentity | null {
91
+ const identity = parseRecordPageUrl(currentPath, basePath)
92
+ if (!identity || identity.role !== 'edit') return null
93
+ return { resourceSlug: identity.resourceSlug, recordId: identity.recordId }
94
+ }