@flamingo-stack/openframe-frontend-core 0.0.848 → 0.0.849

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 (117) hide show
  1. package/dist/build/export-map.json +1 -1
  2. package/dist/{chunk-Y4BG7SPX.cjs → chunk-36XWCVSM.cjs} +63 -63
  3. package/dist/{chunk-YXKAHQYS.cjs → chunk-533QK4R6.cjs} +2 -1
  4. package/dist/{chunk-5HOWR4TG.cjs → chunk-5CBI2ZYV.cjs} +5 -5
  5. package/dist/{chunk-NYT6IBIX.cjs → chunk-5PIR77V5.cjs} +4 -4
  6. package/dist/{chunk-IIUZE73M.cjs → chunk-6AJYGXXS.cjs} +14 -14
  7. package/dist/{chunk-U7UBYJEZ.cjs → chunk-BU2PSRAS.cjs} +5 -5
  8. package/dist/{chunk-I3YRYS23.cjs → chunk-C3P7IUTU.cjs} +37 -12
  9. package/dist/{chunk-O4BXHCMK.cjs → chunk-FRG724DU.cjs} +2 -2
  10. package/dist/{chunk-YAW7CHLV.cjs → chunk-FXLROQUT.cjs} +41 -38
  11. package/dist/{chunk-7YJQTQPV.cjs → chunk-IG6ROHPS.cjs} +46 -46
  12. package/dist/{chunk-INA2FX2N.cjs → chunk-IHY7E4EX.cjs} +2 -2
  13. package/dist/{chunk-Y2ZWWIUA.cjs → chunk-IN3LA2FU.cjs} +2 -2
  14. package/dist/{chunk-7LE4HWHA.cjs → chunk-KXBZCUDW.cjs} +11 -11
  15. package/dist/{chunk-C3WZXOZJ.cjs → chunk-MC3L525K.cjs} +3 -3
  16. package/dist/{chunk-7DW3LZ52.cjs → chunk-PV2XQJ2R.cjs} +92 -171
  17. package/dist/{chunk-GASFYPGH.cjs → chunk-R5JPZ6TY.cjs} +14 -14
  18. package/dist/{chunk-MWYEROAP.cjs → chunk-SHQY4GOE.cjs} +55 -55
  19. package/dist/{chunk-VW4446JR.cjs → chunk-TEKN6TJ5.cjs} +14 -14
  20. package/dist/{chunk-QUSCSYHJ.cjs → chunk-TX4NTH22.cjs} +45 -26
  21. package/dist/{chunk-2V6FCVUL.cjs → chunk-YLETC7LP.cjs} +187 -169
  22. package/dist/{chunk-OCJXOSIH.cjs → chunk-YYHQY3K6.cjs} +30 -30
  23. package/dist/{chunk-74Z34I2C.cjs → chunk-Z5UCDEKZ.cjs} +4 -4
  24. package/dist/{chunk-IUZVOQXP.cjs → chunk-ZY34R37A.cjs} +45 -45
  25. package/dist/{cloud-tenants-YAZHLPOQ.cjs → cloud-tenants-HKUUEUAY.cjs} +7 -7
  26. package/dist/components/case-studies/index.cjs +21 -21
  27. package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
  28. package/dist/components/chat/entity-cards/dispatch.js +1 -0
  29. package/dist/components/chat/index.cjs +5 -5
  30. package/dist/components/contact/index.cjs +8 -8
  31. package/dist/components/docs/doc-viewer.d.ts +7 -7
  32. package/dist/components/docs/doc-viewer.d.ts.map +1 -1
  33. package/dist/components/docs/doc-viewer.js +29 -16
  34. package/dist/components/docs/docs-hub-page.d.ts +1 -1
  35. package/dist/components/docs/docs-hub-page.d.ts.map +1 -1
  36. package/dist/components/docs/docs-hub-page.js +4 -11
  37. package/dist/components/docs/index.cjs +11 -11
  38. package/dist/components/docs/use-document-tree.d.ts.map +1 -1
  39. package/dist/components/docs/use-document-tree.js +24 -24
  40. package/dist/components/embeds/claude-embed.d.ts +2 -2
  41. package/dist/components/embeds/claude-embed.d.ts.map +1 -1
  42. package/dist/components/embeds/claude-embed.js +3 -3
  43. package/dist/components/embeds/embed-iframe.d.ts +5 -3
  44. package/dist/components/embeds/embed-iframe.d.ts.map +1 -1
  45. package/dist/components/embeds/embed-iframe.js +4 -3
  46. package/dist/components/embeds/embed-viewer-frame.d.ts +12 -9
  47. package/dist/components/embeds/embed-viewer-frame.d.ts.map +1 -1
  48. package/dist/components/embeds/embed-viewer-frame.js +21 -7
  49. package/dist/components/embeds/figma-embed.d.ts +4 -2
  50. package/dist/components/embeds/figma-embed.d.ts.map +1 -1
  51. package/dist/components/embeds/figma-embed.js +4 -3
  52. package/dist/components/embeds/file-download-card.d.ts +3 -1
  53. package/dist/components/embeds/file-download-card.d.ts.map +1 -1
  54. package/dist/components/embeds/file-download-card.js +18 -3
  55. package/dist/components/embeds/google-sheets-viewer.d.ts +3 -1
  56. package/dist/components/embeds/google-sheets-viewer.d.ts.map +1 -1
  57. package/dist/components/embeds/google-sheets-viewer.js +7 -4
  58. package/dist/components/embeds/index.cjs +8 -8
  59. package/dist/components/embeds/pdf-viewer.d.ts +3 -1
  60. package/dist/components/embeds/pdf-viewer.d.ts.map +1 -1
  61. package/dist/components/embeds/pdf-viewer.js +6 -2
  62. package/dist/components/faq/index.cjs +9 -9
  63. package/dist/components/features/index.cjs +7 -7
  64. package/dist/components/help-center-pages/index.cjs +81 -81
  65. package/dist/components/index.cjs +49 -49
  66. package/dist/components/meeting-scheduler/index.cjs +32 -32
  67. package/dist/components/navigation/index.cjs +10 -10
  68. package/dist/components/onboarding-guides/index.cjs +10 -10
  69. package/dist/components/product-demo/index.cjs +16 -16
  70. package/dist/components/related-content/index.cjs +4 -4
  71. package/dist/components/tickets/index.cjs +12 -12
  72. package/dist/components/ui/index.cjs +7 -7
  73. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +1 -1
  74. package/dist/components/ui/markdown/rich/rich-markdown-renderer.js +7 -3
  75. package/dist/{devices-IZROCLFK.cjs → devices-P7M4Z7VP.cjs} +8 -8
  76. package/dist/{embeddable-chat-ETW6S22E.cjs → embeddable-chat-322NDFP5.cjs} +74 -74
  77. package/dist/index.cjs +15 -11
  78. package/dist/{knowledge-4IRWLTNW.cjs → knowledge-TC7JLOWI.cjs} +8 -8
  79. package/dist/{logs-EFDGY5IO.cjs → logs-GPOYCP4B.cjs} +14 -14
  80. package/dist/{policies-3KEXZ5BP.cjs → policies-ZUHOUMDD.cjs} +11 -11
  81. package/dist/{scripts-PCGTZLZL.cjs → scripts-FOEVDGTH.cjs} +12 -12
  82. package/dist/{software-update-YCDNVFJE.cjs → software-update-XGTMNFST.cjs} +10 -10
  83. package/dist/types/doc-source.d.ts +2 -2
  84. package/dist/types/doc-source.d.ts.map +1 -1
  85. package/dist/utils/doc-tree-nav.d.ts +7 -0
  86. package/dist/utils/doc-tree-nav.d.ts.map +1 -1
  87. package/dist/utils/doc-tree-nav.js +19 -0
  88. package/dist/utils/index.cjs +25 -2
  89. package/dist/utils/list-url.d.ts.map +1 -1
  90. package/dist/utils/list-url.js +2 -1
  91. package/dist/utils/source-grouping.d.ts +2 -2
  92. package/dist/utils/source-grouping.d.ts.map +1 -1
  93. package/dist/utils/source-grouping.js +1 -1
  94. package/dist/utils/source-icons.d.ts.map +1 -1
  95. package/dist/utils/source-icons.js +3 -0
  96. package/package.json +1 -1
  97. package/src/components/chat/entity-cards/dispatch.tsx +3 -0
  98. package/src/components/docs/doc-viewer.tsx +56 -35
  99. package/src/components/docs/docs-hub-page.tsx +13 -37
  100. package/src/components/docs/use-document-tree.ts +33 -23
  101. package/src/components/embeds/claude-embed.tsx +4 -4
  102. package/src/components/embeds/embed-iframe.tsx +8 -5
  103. package/src/components/embeds/embed-viewer-frame.tsx +35 -15
  104. package/src/components/embeds/figma-embed.tsx +9 -4
  105. package/src/components/embeds/file-download-card.tsx +28 -4
  106. package/src/components/embeds/google-sheets-viewer.tsx +9 -3
  107. package/src/components/embeds/pdf-viewer.tsx +9 -2
  108. package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +4 -0
  109. package/src/types/doc-source.ts +2 -2
  110. package/src/utils/doc-tree-nav.ts +27 -0
  111. package/src/utils/list-url.ts +2 -1
  112. package/src/utils/source-grouping.ts +2 -2
  113. package/src/utils/source-icons.ts +3 -0
  114. package/dist/components/docs/skeletons.d.ts +0 -25
  115. package/dist/components/docs/skeletons.d.ts.map +0 -1
  116. package/dist/components/docs/skeletons.js +0 -83
  117. package/src/components/docs/skeletons.tsx +0 -131
@@ -1,14 +1,23 @@
1
1
  import { FileText, Download } from 'lucide-react';
2
2
  import { formatFileSize } from '../../utils';
3
+ import { InteractiveSkeleton, TextLineSkeleton } from '../loading/unified-skeleton';
3
4
  import { Button } from '../ui';
5
+ import { useLoadingScope } from '../ui/loading-scope';
4
6
 
5
7
  export interface FileDownloadCardProps {
6
8
  fileName?: string;
7
9
  mimeType?: string;
8
10
  fileSize?: number;
9
11
  fileUrl?: string;
12
+ /** The file is being read: the card draws its loading form. A loading scope does the same. */
13
+ loading?: boolean;
10
14
  }
11
15
 
16
+ /** The card's boxes, shared by the card and its loading form. */
17
+ const FILE_CARD_OUTER_CLASS = 'flex flex-col items-center justify-center py-16';
18
+ const FILE_CARD_CLASS = 'w-full max-w-md space-y-4 rounded-xl border border-ods-border bg-ods-card p-8 text-center';
19
+ const FILE_ICON_CLASS = 'mx-auto h-16 w-16 text-ods-text-secondary';
20
+
12
21
  /**
13
22
  * Generic downloadable-file card for the `file` document type. Used by
14
23
  * `<DocsHubPage>`'s default `documentTypeRenderers.file`. Embedders can
@@ -18,11 +27,26 @@ export interface FileDownloadCardProps {
18
27
  * renders the filename + type + size so the user knows what they were
19
28
  * about to download).
20
29
  */
21
- export function FileDownloadCard({ fileName, mimeType, fileSize, fileUrl }: FileDownloadCardProps) {
30
+ export function FileDownloadCard({ fileName, mimeType, fileSize, fileUrl, loading = false }: FileDownloadCardProps) {
31
+ // In a loading scope the file is being read: the card draws its own loading form, in its own boxes.
32
+ if (useLoadingScope() || loading) {
33
+ return (
34
+ <div className={FILE_CARD_OUTER_CLASS}>
35
+ <div className={FILE_CARD_CLASS}>
36
+ <FileText className={FILE_ICON_CLASS} />
37
+ <div>
38
+ <TextLineSkeleton type="h3" className="mx-auto w-2/3" />
39
+ <TextLineSkeleton type="h6" className="mx-auto mt-2 w-1/2" />
40
+ </div>
41
+ <InteractiveSkeleton.Button className="mx-auto" />
42
+ </div>
43
+ </div>
44
+ );
45
+ }
22
46
  return (
23
- <div className="flex flex-col items-center justify-center py-16">
24
- <div className="w-full max-w-md space-y-4 rounded-xl border border-ods-border bg-ods-card p-8 text-center">
25
- <FileText className="mx-auto h-16 w-16 text-ods-text-secondary" />
47
+ <div className={FILE_CARD_OUTER_CLASS}>
48
+ <div className={FILE_CARD_CLASS}>
49
+ <FileText className={FILE_ICON_CLASS} />
26
50
  <div>
27
51
  <h3 className="text-ods-text-primary text-h3">{fileName || 'File'}</h3>
28
52
  <div className="mt-2 flex items-center justify-center gap-3 text-ods-text-secondary text-h6">
@@ -4,20 +4,25 @@ import { ExternalLink } from 'lucide-react';
4
4
  import { toGoogleSheetsEmbedUrl, toGoogleSheetsOriginalUrl } from '../../utils/embed-url-converters';
5
5
  import { GoogleSheetsIcon } from '../icons-v2-generated';
6
6
  import { Button } from '../ui';
7
+ import { useLoadingScope } from '../ui/loading-scope';
7
8
  import { EmbedViewerFrame } from './embed-viewer-frame';
8
9
 
9
10
  export interface GoogleSheetsViewerProps {
10
11
  externalUrl: string;
11
12
  fileName?: string;
12
13
  height?: string;
14
+ /** The document is being read: the viewer draws its loading form. A loading scope does the same. */
15
+ loading?: boolean;
13
16
  }
14
17
 
15
- export function GoogleSheetsViewer({ externalUrl, fileName, height }: GoogleSheetsViewerProps) {
18
+ export function GoogleSheetsViewer({ externalUrl, fileName, height, loading = false }: GoogleSheetsViewerProps) {
16
19
  const displayName = fileName || 'Google Sheet';
20
+ // In a loading scope the document is being read: the frame draws its loading form, never "not configured".
21
+ const isLoading = useLoadingScope() || loading;
17
22
 
18
23
  // Historical shape: no URL at all → standalone empty state with NO header
19
24
  // (the frame's empty body keeps the header — that's the figma behavior).
20
- if (!externalUrl) {
25
+ if (!externalUrl && !isLoading) {
21
26
  return (
22
27
  <div className="flex flex-col items-center justify-center py-16 text-center">
23
28
  <GoogleSheetsIcon className="mb-4 h-16 w-16 text-ods-text-secondary" />
@@ -43,8 +48,9 @@ export function GoogleSheetsViewer({ externalUrl, fileName, height }: GoogleShee
43
48
  Open in Google Sheets
44
49
  </Button>
45
50
  }
46
- src={toGoogleSheetsEmbedUrl(externalUrl)}
51
+ src={externalUrl ? toGoogleSheetsEmbedUrl(externalUrl) : null}
47
52
  height={height}
53
+ loading={loading}
48
54
  />
49
55
  );
50
56
  }
@@ -3,6 +3,7 @@
3
3
  import { Download, Eye } from 'lucide-react';
4
4
  import { AdobePdfIcon } from '../icons-v2-generated';
5
5
  import { Button } from '../ui';
6
+ import { useLoadingScope } from '../ui/loading-scope';
6
7
  import { EmbedViewerFrame } from './embed-viewer-frame';
7
8
 
8
9
  export interface PdfViewerProps {
@@ -11,13 +12,17 @@ export interface PdfViewerProps {
11
12
  onPreview?: () => void;
12
13
  onDownload?: () => void;
13
14
  height?: string;
15
+ /** The document is being read: the viewer draws its loading form. A loading scope does the same. */
16
+ loading?: boolean;
14
17
  }
15
18
 
16
- export function PdfViewer({ src, fileName, onPreview, onDownload, height }: PdfViewerProps) {
19
+ export function PdfViewer({ src, fileName, onPreview, onDownload, height, loading = false }: PdfViewerProps) {
17
20
  const displayName = fileName || 'PDF Document';
21
+ // In a loading scope the document is being read: the frame draws its loading form, never "not available".
22
+ const isLoading = useLoadingScope() || loading;
18
23
 
19
24
  // Historical shape: no src at all → standalone empty state with NO header.
20
- if (!src) {
25
+ if (!src && !isLoading) {
21
26
  return (
22
27
  <div className="flex flex-col items-center justify-center py-16 text-center">
23
28
  <AdobePdfIcon className="mb-4 h-16 w-16 text-ods-text-secondary" />
@@ -57,6 +62,8 @@ export function PdfViewer({ src, fileName, onPreview, onDownload, height }: PdfV
57
62
  </div>
58
63
  }
59
64
  src={src}
65
+ loadingActionCount={2}
66
+ loading={loading}
60
67
  height={height}
61
68
  />
62
69
  );
@@ -101,6 +101,7 @@ const RichMarkdownInner: React.FC<InnerProps> = ({
101
101
  demoteMarkdownH1ToH2,
102
102
  skeletonSections,
103
103
  skeletonLines,
104
+ skeletonTitle,
104
105
  }) => {
105
106
  const { ogScraperUrl } = useRichMarkdownRuntime();
106
107
 
@@ -158,6 +159,7 @@ const RichMarkdownInner: React.FC<InnerProps> = ({
158
159
  allowRemoteMedia
159
160
  skeletonSections={skeletonSections}
160
161
  skeletonLines={skeletonLines}
162
+ skeletonTitle={skeletonTitle}
161
163
  />
162
164
  );
163
165
  };
@@ -174,6 +176,7 @@ const RichMarkdownRendererImpl: React.FC<RichMarkdownRendererProps> = ({
174
176
  demoteMarkdownH1ToH2 = false,
175
177
  skeletonSections,
176
178
  skeletonLines,
179
+ skeletonTitle,
177
180
  // Runtime overrides; provider fills the defaults
178
181
  redditProxyUrl,
179
182
  twitterProxyUrl,
@@ -199,6 +202,7 @@ const RichMarkdownRendererImpl: React.FC<RichMarkdownRendererProps> = ({
199
202
  demoteMarkdownH1ToH2={demoteMarkdownH1ToH2}
200
203
  skeletonSections={skeletonSections}
201
204
  skeletonLines={skeletonLines}
205
+ skeletonTitle={skeletonTitle}
202
206
  />
203
207
  </RichMarkdownRuntimeProvider>
204
208
  );
@@ -75,12 +75,12 @@ export interface DocSourceDal<Client = unknown> {
75
75
  * Doc-source registry id. The lib's `<DocViewer>` is generic over this union
76
76
  * — the hub's `DOC_SOURCES` registry defines the actual ids. Listed here as a
77
77
  * type-only union so the lib can flow the id into `DocRenderHandlers.sourceId`
78
- * without callers having to cast `string` → `'openframe-docs' | 'data-room-docs'`.
78
+ * without callers having to cast `string` to the union.
79
79
  *
80
80
  * Adding a new source = add the id here AND register it in the hub. The lib
81
81
  * never reaches into the registry — this is purely a type-narrowing handle.
82
82
  */
83
- export type DocSourceId = 'openframe-docs' | 'data-room-docs';
83
+ export type DocSourceId = 'openframe-docs' | 'data-room-docs' | 'company-policies';
84
84
 
85
85
  /**
86
86
  * Result returned by the resolve-link endpoint. Discriminator-style: `success`
@@ -102,3 +102,30 @@ export function getDocSourceDefaultPath(
102
102
  const firstFolderWithReadme = structure.find(node => node.type === 'folder' && node.hasReadme && !!node.path);
103
103
  return firstFolderWithReadme?.path ?? null;
104
104
  }
105
+
106
+ /** The first document under a folder (its own files first, then each subfolder's, in order), never a diagram source. */
107
+ export function findFirstDocPath(folder: DocNode): string | null {
108
+ const children = folder.children ?? [];
109
+ for (const child of children) {
110
+ if (child.type === 'file' && !child.path.toLowerCase().endsWith('.mmd')) return child.path;
111
+ }
112
+ for (const child of children) {
113
+ if (child.type === 'folder') {
114
+ const nested = findFirstDocPath(child);
115
+ if (nested) return nested;
116
+ }
117
+ }
118
+ return null;
119
+ }
120
+
121
+ /**
122
+ * The document a source's root shows: its folder index when the tree has one, else its first document (the rule a
123
+ * folder with no README follows), else null (a tree with no document at all).
124
+ */
125
+ export function rootDocumentPath(
126
+ structure: DocNode[],
127
+ folderIndexFile: string = DEFAULT_FOLDER_INDEX_FILE,
128
+ ): string | null {
129
+ if (structure.some(node => node.type === 'file' && node.path === folderIndexFile)) return folderIndexFile;
130
+ return findFirstDocPath({ id: '', name: '', slug: '', path: '', type: 'folder', children: structure });
131
+ }
@@ -99,7 +99,8 @@ const BUILDERS: Record<string, (ids: string[], base: string) => string> = {
99
99
  slack_message: (ids, b) => `${b}/api/slack-community/messages?ids=${ids.join(',')}`,
100
100
  hubspot_ticket: (ids, b) => `${b}/api/tickets/internal?ids=${ids.join(',')}`,
101
101
  hubspot_ticket_anon: (ids, b) => `${b}/api/tickets/known-issues?ids=${ids.join(',')}`,
102
- data_room_doc: (ids, b) => `${b}/api/data-room/documents?ids=${ids.join(',')}`,
102
+ data_room_doc: (ids, b) => `${b}/api/libraries/data-room/documents?ids=${ids.join(',')}`,
103
+ policy_doc: (ids, b) => `${b}/api/libraries/company-policies/documents?ids=${ids.join(',')}`,
103
104
  markdown: (ids, b) => `${b}/api/docs/pages?ids=${ids.join(',')}`,
104
105
  financial_kpi: (ids, b) => `${b}/api/financials/kpis?ids=${ids.join(',')}`,
105
106
  cap_table: (ids, b) => `${b}/api/financials/cap-table?ids=${ids.join(',')}`,
@@ -27,13 +27,13 @@ import { defaultDocumentTypeForTableId, getSourceLabel } from './source-icons';
27
27
 
28
28
  /**
29
29
  * Doc-table documentTypes: whole documents with their own viewer (markdown =
30
- * product docs, data_room_doc = data room). They carry an in-app `path` (handed
30
+ * product docs, data_room_doc = data room, policy_doc = company policies). They carry an in-app `path` (handed
31
31
  * to the host's composer as the slug), and a server never folds them
32
32
  * into one citation (`groupsByTable`); the strip still draws them as one chip
33
33
  * per table. The hub's per-source contract test pins this list to its
34
34
  * doc-table configs.
35
35
  */
36
- export const DOC_TABLE_TYPES = ['markdown', 'data_room_doc'] as const;
36
+ export const DOC_TABLE_TYPES = ['markdown', 'data_room_doc', 'policy_doc'] as const;
37
37
 
38
38
  /**
39
39
  * Which tables a SERVER folds into one citation: rows of a knowledge table
@@ -29,6 +29,7 @@ export const SOURCE_ICON_NAMES: Record<string, string> = {
29
29
  // Doc tables
30
30
  'openframe-docs': 'openframe',
31
31
  'data-room-docs': 'shield',
32
+ 'company-policies': 'book-open',
32
33
 
33
34
  // CMS / programs
34
35
  'blog-posts': 'newspaper',
@@ -136,6 +137,7 @@ export const SOURCE_LABELS_BY_TABLE: Record<string, string> = {
136
137
  // Doc tables
137
138
  'openframe-docs': 'OpenFrame Docs',
138
139
  'data-room-docs': 'Data Room',
140
+ 'company-policies': 'Company Policies',
139
141
 
140
142
  // CMS / programs
141
143
  'blog-posts': 'Blog Posts',
@@ -242,6 +244,7 @@ export const DEFAULT_DOCUMENT_TYPE_TO_TABLE_ID: Record<string, string> = {
242
244
  // Doc tables
243
245
  markdown: 'openframe-docs',
244
246
  data_room_doc: 'data-room-docs',
247
+ policy_doc: 'company-policies',
245
248
 
246
249
  // CMS / programs
247
250
  blog_post: 'blog-posts',
@@ -1,25 +0,0 @@
1
- export declare function MarkdownSkeleton({ region, }?: {
2
- /** The loading state announces itself (`LoadingRegion`). `false` inside another loading region. Default `true`. */
3
- region?: boolean;
4
- }): import("react").JSX.Element;
5
- /**
6
- * Embed-style skeleton — matches the iframe loading state for `pdf`,
7
- * `google_sheet`, `figma`, and `file` document types. Used by
8
- * `<DocsHubPage>` as the default for non-markdown documentTypes.
9
- *
10
- * The skeleton is documentType-aware so its layout matches the actual
11
- * viewer that will replace it:
12
- * - `pdf` → header with title + TWO buttons (Preview, Download)
13
- * - `google_sheet`/`figma` → header with title + ONE button/toggle
14
- * - `file` → centered FileDownloadCard-style box
15
- * - undefined / others → generic (1-button header)
16
- */
17
- export interface EmbedSkeletonProps {
18
- /** When provided, the header layout matches the eventual viewer's
19
- * button count + arrangement, so the layout doesn't shift on load. */
20
- documentType?: 'pdf' | 'google_sheet' | 'figma' | 'file' | string;
21
- /** The loading state announces itself (`LoadingRegion`). `false` inside another loading region. Default `true`. */
22
- region?: boolean;
23
- }
24
- export declare function EmbedSkeleton({ documentType, region }?: EmbedSkeletonProps): import("react").JSX.Element;
25
- //# sourceMappingURL=skeletons.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"skeletons.d.ts","sourceRoot":"","sources":["../../../src/components/docs/skeletons.tsx"],"names":[],"mappings":"AA2BA,wBAAgB,gBAAgB,CAAC,EAC/B,MAAa,GACd,GAAE;IACD,mHAAmH;IACnH,MAAM,CAAC,EAAE,OAAO,CAAC;CACb,+BA2BL;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IACjC;2EACuE;IACvE,YAAY,CAAC,EAAE,KAAK,GAAG,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAClE,mHAAmH;IACnH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,aAAa,CAAC,EAAE,YAAY,EAAE,MAAa,EAAE,GAAE,kBAAuB,+BAiDrF"}
@@ -1,83 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { cn } from "../../utils/cn.js";
4
- import { EmbedLoadingSkeleton } from "../embeds/embed-iframe.js";
5
- import { LoadingRegion } from "../loading/loading-region.js";
6
- import { TextLineSkeleton, UnifiedSkeleton } from "../loading/unified-skeleton.js";
7
- import { MARKDOWN_H2_CLASS, MARKDOWN_PARAGRAPH_CLASS } from "../ui/markdown/base-components.js";
8
- import { MARKDOWN_RENDERER_CLASS } from "../ui/markdown/engine.js";
9
- import { TEXT_SIZE_PRESETS } from "../ui/markdown/text-size.js";
10
- const MARKDOWN_SKELETON_BLOCKS = [
11
- { kind: "p", lines: 4 },
12
- { kind: "p", lines: 4 },
13
- { kind: "p", lines: 5 },
14
- { kind: "h2" },
15
- { kind: "p", lines: 4 },
16
- { kind: "p", lines: 5 },
17
- { kind: "h2" },
18
- { kind: "p", lines: 3 },
19
- { kind: "p", lines: 4 }
20
- ];
21
- const MARKDOWN_SKELETON_H2_CLASS = cn(MARKDOWN_H2_CLASS, TEXT_SIZE_PRESETS.default.h2);
22
- const MARKDOWN_SKELETON_P_CLASS = cn(MARKDOWN_PARAGRAPH_CLASS, TEXT_SIZE_PRESETS.default.p);
23
- function MarkdownSkeleton({
24
- region = true
25
- } = {}) {
26
- return (
27
- // The renderer's root class, and its box (no margin of its own, like the rendered body): the document's first fold.
28
- /* @__PURE__ */ jsx(LoadingRegion, { label: "Loading the document", announce: region, className: MARKDOWN_RENDERER_CLASS, children: MARKDOWN_SKELETON_BLOCKS.map(
29
- (block, i) => block.kind === "h2" ? (
30
- // biome-ignore lint/suspicious/noArrayIndexKey: skeleton blocks never reorder
31
- /* @__PURE__ */ jsx("h2", { className: MARKDOWN_SKELETON_H2_CLASS, "aria-hidden": true, children: /* @__PURE__ */ jsx(TextLineSkeleton, { type: "inherit", as: "span", className: "w-1/3" }) }, i)
32
- ) : (
33
- // The last block ends the body with no margin, like the rendered one. Its own `last:mb-0` does not apply here:
34
- // the region's status line follows the blocks, so the paragraph is not the last child.
35
- // biome-ignore lint/suspicious/noArrayIndexKey: skeleton blocks never reorder
36
- /* @__PURE__ */ jsx(
37
- "p",
38
- {
39
- className: cn(MARKDOWN_SKELETON_P_CLASS, i === MARKDOWN_SKELETON_BLOCKS.length - 1 && "mb-0"),
40
- "aria-hidden": true,
41
- children: /* @__PURE__ */ jsx(TextLineSkeleton, { type: "inherit", as: "span", lines: block.lines, className: "w-full" })
42
- },
43
- i
44
- )
45
- )
46
- ) })
47
- );
48
- }
49
- function EmbedSkeleton({ documentType, region = true } = {}) {
50
- if (documentType === "file") {
51
- return /* @__PURE__ */ jsx(
52
- LoadingRegion,
53
- {
54
- label: "Loading the document",
55
- announce: region,
56
- className: "flex flex-col items-center justify-center py-16",
57
- children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-md space-y-4 rounded-xl border border-ods-border bg-ods-card p-8 text-center", children: [
58
- /* @__PURE__ */ jsx(UnifiedSkeleton, { className: "mx-auto h-16 w-16 rounded" }),
59
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
60
- /* @__PURE__ */ jsx(UnifiedSkeleton, { className: "mx-auto h-5 w-2/3 rounded" }),
61
- /* @__PURE__ */ jsx(UnifiedSkeleton, { className: "mx-auto h-4 w-1/2 rounded" })
62
- ] }),
63
- /* @__PURE__ */ jsx(UnifiedSkeleton, { className: "h-10 w-full rounded" })
64
- ] })
65
- }
66
- );
67
- }
68
- const buttonCount = documentType === "pdf" ? 2 : 1;
69
- return /* @__PURE__ */ jsxs(LoadingRegion, { label: "Loading the document", announce: region, className: "space-y-4", children: [
70
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 content-sm:flex-row content-sm:items-center content-sm:justify-between", children: [
71
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
72
- /* @__PURE__ */ jsx(UnifiedSkeleton, { className: "h-5 w-5 shrink-0 rounded" }),
73
- /* @__PURE__ */ jsx(UnifiedSkeleton, { className: "h-6 w-2/3 rounded" })
74
- ] }),
75
- /* @__PURE__ */ jsx("div", { className: "flex w-full items-center gap-2 content-sm:w-auto", children: Array.from({ length: buttonCount }).map((_, i) => /* @__PURE__ */ jsx(UnifiedSkeleton, { className: "h-10 w-full flex-1 rounded content-sm:w-32 content-sm:flex-initial" }, i)) })
76
- ] }),
77
- /* @__PURE__ */ jsx(EmbedLoadingSkeleton, { region: false })
78
- ] });
79
- }
80
- export {
81
- EmbedSkeleton,
82
- MarkdownSkeleton
83
- };
@@ -1,131 +0,0 @@
1
- import { cn } from '../../utils/cn';
2
- import { EmbedLoadingSkeleton } from '../embeds/embed-iframe';
3
- import { LoadingRegion } from '../loading/loading-region';
4
- import { TextLineSkeleton, UnifiedSkeleton } from '../loading/unified-skeleton';
5
- import { MARKDOWN_H2_CLASS, MARKDOWN_PARAGRAPH_CLASS } from '../ui/markdown/base-components';
6
- import { MARKDOWN_RENDERER_CLASS } from '../ui/markdown/engine';
7
- import { TEXT_SIZE_PRESETS } from '../ui/markdown/text-size';
8
- /**
9
- * Text-style skeleton — matches a rendered markdown article layout.
10
- * Used by `<DocsHubPage>` as the default for `markdown` (and unknown
11
- * document types). Embedders can override via `renderSkeleton`.
12
- */
13
- /** Paragraphs and headings the markdown skeleton draws (a document's first fold), with each paragraph's lines. */
14
- const MARKDOWN_SKELETON_BLOCKS = [
15
- { kind: 'p', lines: 4 },
16
- { kind: 'p', lines: 4 },
17
- { kind: 'p', lines: 5 },
18
- { kind: 'h2' },
19
- { kind: 'p', lines: 4 },
20
- { kind: 'p', lines: 5 },
21
- { kind: 'h2' },
22
- { kind: 'p', lines: 3 },
23
- { kind: 'p', lines: 4 },
24
- ] as const;
25
- const MARKDOWN_SKELETON_H2_CLASS = cn(MARKDOWN_H2_CLASS, TEXT_SIZE_PRESETS.default.h2);
26
- const MARKDOWN_SKELETON_P_CLASS = cn(MARKDOWN_PARAGRAPH_CLASS, TEXT_SIZE_PRESETS.default.p);
27
-
28
- export function MarkdownSkeleton({
29
- region = true,
30
- }: {
31
- /** The loading state announces itself (`LoadingRegion`). `false` inside another loading region. Default `true`. */
32
- region?: boolean;
33
- } = {}) {
34
- // The rendered document's own heading and paragraph elements (the markdown renderer's default preset), each line a
35
- // bar of the element's line box.
36
- return (
37
- // The renderer's root class, and its box (no margin of its own, like the rendered body): the document's first fold.
38
- <LoadingRegion label="Loading the document" announce={region} className={MARKDOWN_RENDERER_CLASS}>
39
- {MARKDOWN_SKELETON_BLOCKS.map((block, i) =>
40
- block.kind === 'h2' ? (
41
- // biome-ignore lint/suspicious/noArrayIndexKey: skeleton blocks never reorder
42
- <h2 key={i} className={MARKDOWN_SKELETON_H2_CLASS} aria-hidden>
43
- <TextLineSkeleton type="inherit" as="span" className="w-1/3" />
44
- </h2>
45
- ) : (
46
- // The last block ends the body with no margin, like the rendered one. Its own `last:mb-0` does not apply here:
47
- // the region's status line follows the blocks, so the paragraph is not the last child.
48
- // biome-ignore lint/suspicious/noArrayIndexKey: skeleton blocks never reorder
49
- <p
50
- key={i}
51
- className={cn(MARKDOWN_SKELETON_P_CLASS, i === MARKDOWN_SKELETON_BLOCKS.length - 1 && 'mb-0')}
52
- aria-hidden
53
- >
54
- <TextLineSkeleton type="inherit" as="span" lines={block.lines} className="w-full" />
55
- </p>
56
- ),
57
- )}
58
- </LoadingRegion>
59
- );
60
- }
61
-
62
- /**
63
- * Embed-style skeleton — matches the iframe loading state for `pdf`,
64
- * `google_sheet`, `figma`, and `file` document types. Used by
65
- * `<DocsHubPage>` as the default for non-markdown documentTypes.
66
- *
67
- * The skeleton is documentType-aware so its layout matches the actual
68
- * viewer that will replace it:
69
- * - `pdf` → header with title + TWO buttons (Preview, Download)
70
- * - `google_sheet`/`figma` → header with title + ONE button/toggle
71
- * - `file` → centered FileDownloadCard-style box
72
- * - undefined / others → generic (1-button header)
73
- */
74
- export interface EmbedSkeletonProps {
75
- /** When provided, the header layout matches the eventual viewer's
76
- * button count + arrangement, so the layout doesn't shift on load. */
77
- documentType?: 'pdf' | 'google_sheet' | 'figma' | 'file' | string;
78
- /** The loading state announces itself (`LoadingRegion`). `false` inside another loading region. Default `true`. */
79
- region?: boolean;
80
- }
81
-
82
- export function EmbedSkeleton({ documentType, region = true }: EmbedSkeletonProps = {}) {
83
- // Centered card shape for the `file` documentType — matches
84
- // `<FileDownloadCard>`'s `flex flex-col items-center justify-center py-16`
85
- // + bordered card with icon, name, type/size row, Download button.
86
- if (documentType === 'file') {
87
- return (
88
- <LoadingRegion
89
- label="Loading the document"
90
- announce={region}
91
- className="flex flex-col items-center justify-center py-16"
92
- >
93
- <div className="w-full max-w-md space-y-4 rounded-xl border border-ods-border bg-ods-card p-8 text-center">
94
- <UnifiedSkeleton className="mx-auto h-16 w-16 rounded" />
95
- <div className="space-y-2">
96
- <UnifiedSkeleton className="mx-auto h-5 w-2/3 rounded" />
97
- <UnifiedSkeleton className="mx-auto h-4 w-1/2 rounded" />
98
- </div>
99
- <UnifiedSkeleton className="h-10 w-full rounded" />
100
- </div>
101
- </LoadingRegion>
102
- );
103
- }
104
-
105
- // PDF viewer has TWO buttons (Preview + Download); Sheets / Figma
106
- // render ONE (Open / view-toggle). Default to one for unknown types.
107
- const buttonCount = documentType === 'pdf' ? 2 : 1;
108
-
109
- return (
110
- <LoadingRegion label="Loading the document" announce={region} className="space-y-4">
111
- {/* Header — matches the actual viewer's
112
- * `flex flex-col gap-3 content-sm:flex-row content-sm:items-center content-sm:justify-between`
113
- * (mobile-stacked, desktop-row). */}
114
- <div className="flex flex-col gap-3 content-sm:flex-row content-sm:items-center content-sm:justify-between">
115
- {/* Left: icon + title */}
116
- <div className="flex min-w-0 flex-1 items-center gap-2">
117
- <UnifiedSkeleton className="h-5 w-5 shrink-0 rounded" />
118
- <UnifiedSkeleton className="h-6 w-2/3 rounded" />
119
- </div>
120
- {/* Right: 1 or 2 buttons. Mobile = full-width; desktop = auto. */}
121
- <div className="flex w-full items-center gap-2 content-sm:w-auto">
122
- {Array.from({ length: buttonCount }).map((_, i) => (
123
- <UnifiedSkeleton key={i} className="h-10 w-full flex-1 rounded content-sm:w-32 content-sm:flex-initial" />
124
- ))}
125
- </div>
126
- </div>
127
- {/* Body: the iframe viewer's own loading box (its default `calc(100vh - 250px)` height). */}
128
- <EmbedLoadingSkeleton region={false} />
129
- </LoadingRegion>
130
- );
131
- }