@athenaintel/react 0.10.38 → 0.10.40

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.
package/README.md CHANGED
@@ -144,13 +144,19 @@ Set `linkClicks={{ interceptAthenaCitations: false }}` to keep Athena citation l
144
144
 
145
145
  ## Standalone Asset Embeds
146
146
 
147
- Use `AthenaAssetEmbed` to render a native Athena asset without chat, thread history, tabs, or the SDK split-pane layout. Full mode supports documents, spreadsheets, and presentations.
147
+ Use `AthenaAssetEmbed` to render a native Athena asset without chat, thread history, tabs, or the SDK split-pane layout. It defaults to the editable, full native asset experience (`readOnly={false}` and `displayMode="full"`). The embed token and the current user must still have edit permission; otherwise Athena renders the asset read-only.
148
148
 
149
149
  ```tsx
150
- import { AthenaAssetEmbed, AthenaProvider } from '@athenaintel/react';
150
+ import { useState } from 'react';
151
+ import {
152
+ AthenaAssetEmbed,
153
+ AthenaProvider,
154
+ type AthenaAssetCitationReference,
155
+ } from '@athenaintel/react';
151
156
 
152
157
  function AssetView() {
153
- const [linkedReference, setLinkedReference] = useState(null);
158
+ const [linkedReference, setLinkedReference] =
159
+ useState<AthenaAssetCitationReference | null>(null);
154
160
 
155
161
  return (
156
162
  <AthenaProvider config={{ token: accessToken }}>
@@ -158,7 +164,7 @@ function AssetView() {
158
164
  <AthenaAssetEmbed
159
165
  assetId="asset_123"
160
166
  displayMode="full"
161
- readOnly
167
+ readOnly={false}
162
168
  onCitationClick={({ reference, sourceAssetId }) => {
163
169
  console.log('Citation clicked', { reference, sourceAssetId });
164
170
  }}
@@ -173,7 +179,7 @@ function AssetView() {
173
179
  assetId={linkedReference.id}
174
180
  reference={linkedReference}
175
181
  displayMode="full"
176
- readOnly
182
+ readOnly={false}
177
183
  />
178
184
  )}
179
185
  </div>
@@ -187,8 +193,44 @@ When `onCitationClick` is provided, citation navigation is delegated to the host
187
193
  `onCitationAction` handles actions initiated from a citation popover. It currently receives `action: 'open-in-spaces'` when the user clicks the (+) button. Providing the handler delegates that action to the host by default. Set `citationActionBehavior="browser"` to observe the event while preserving Athena's default navigation; requesting host mode without a handler safely falls back to browser behavior.
188
194
 
189
195
  Pass the callback's complete `reference` to the linked `AthenaAssetEmbed`, rather than storing only
190
- `reference.id`. The embed uses the reference anchor to navigate PDFs to the cited page. Updating the
191
- reference also navigates when the host opens another citation in the same asset.
196
+ `reference.id`. The embed uses the reference anchor to navigate PDFs to the cited page and highlight
197
+ the cited excerpt or rectangular region. Updating the reference also navigates when the host opens
198
+ another citation in the same asset.
199
+
200
+ If the host starts with an Athena citation URL/string instead of an
201
+ `onCitationAction` event, parse it and pass the returned `reference` directly to the embed:
202
+
203
+ ```tsx
204
+ import {
205
+ AthenaAssetEmbed,
206
+ parseAthenaCitationLink,
207
+ } from '@athenaintel/react';
208
+
209
+ const citation = parseAthenaCitationLink({
210
+ href: citationString,
211
+ appUrl: 'https://app.athenaintel.com',
212
+ });
213
+
214
+ return citation ? (
215
+ <AthenaAssetEmbed
216
+ assetId={citation.assetId}
217
+ reference={citation.reference}
218
+ displayMode="full"
219
+ readOnly={false}
220
+ />
221
+ ) : null;
222
+ ```
223
+
224
+ For example, this citation opens the PDF directly at page 34:
225
+
226
+ ```text
227
+ https://app.athenaintel.com/dashboard/spaces/?asset_ids=asset_pdf&anchor=page&page=34&excerpt=Term%20debt
228
+ ```
229
+
230
+ The important query parameters are `asset_ids`, `anchor=page`, `page`, and `excerpt`. Page ranges,
231
+ text anchors, and positioned citations are also preserved by `parseAthenaCitationLink`. A
232
+ `page_rect` may include `unit=percent` (the default) or `unit=point`; retain the unit so the region
233
+ maps to the correct PDF coordinates.
192
234
 
193
235
  ## Theming
194
236
 
@@ -6,7 +6,7 @@ export interface AthenaAssetEmbedProps extends Omit<IframeHTMLAttributes<HTMLIFr
6
6
  reference?: AthenaAssetCitationReference;
7
7
  /** Defaults to the native full asset experience. */
8
8
  displayMode?: "minimal" | "full";
9
- /** Defaults to true. */
9
+ /** Defaults to false so authorized users can edit the embedded asset. */
10
10
  readOnly?: boolean;
11
11
  expiresInSeconds?: number;
12
12
  citationBehavior?: AthenaAssetCitationBehavior;
@@ -2,9 +2,11 @@ import type { AthenaAssetCitationReference } from './asset-embed-messages';
2
2
  export interface UseAssetEmbedOptions {
3
3
  readOnly?: boolean;
4
4
  expiresInSeconds?: number;
5
- /** Native Olympus surface rendered by the iframe. Defaults to `minimal`. */
5
+ /** Native Olympus surface rendered by the iframe. Defaults to `full`. */
6
6
  displayMode?: 'minimal' | 'full';
7
7
  }
8
+ export declare const DEFAULT_ASSET_EMBED_READ_ONLY = false;
9
+ export declare const DEFAULT_ASSET_EMBED_DISPLAY_MODE: 'full';
8
10
  export interface UseAssetEmbedResult {
9
11
  embedUrl: string | null;
10
12
  isLoading: boolean;
@@ -1,3 +1,4 @@
1
+ import type { AthenaAssetCitationReference } from '../assets/asset-embed-messages';
1
2
  import { type AssetType } from '../assets/asset-panel-store';
2
3
  import type { AthenaCitationLinkHandler, AthenaLinkClickHandler } from '../provider/citation-links';
3
4
  export interface ParsedAthenaCitationLink {
@@ -5,6 +6,8 @@ export interface ParsedAthenaCitationLink {
5
6
  assetId: string;
6
7
  assetIds: string[];
7
8
  assetType: AssetType | null;
9
+ /** Complete target that can be passed directly to AthenaAssetEmbed.reference. */
10
+ reference: AthenaAssetCitationReference;
8
11
  }
9
12
  export declare const parseAthenaCitationLink: ({ href, appUrl, }: {
10
13
  href: string;
package/dist/index.cjs CHANGED
@@ -47521,6 +47521,60 @@ const ASSET_TYPE_ALIASES = {
47521
47521
  word_document: "document"
47522
47522
  };
47523
47523
  const isAthenaSpacesPath = (url) => url.pathname.replace(/\/+$/, "") === "/dashboard/spaces";
47524
+ const getFiniteNumber = (url, key) => {
47525
+ const value = url.searchParams.get(key);
47526
+ if (value === null || value.trim() === "") return null;
47527
+ const parsed = Number(value);
47528
+ return Number.isFinite(parsed) ? parsed : null;
47529
+ };
47530
+ const parseCitationReference = ({
47531
+ url,
47532
+ assetId
47533
+ }) => {
47534
+ const reference2 = { id: assetId };
47535
+ const anchorType = url.searchParams.get("anchor");
47536
+ const page = getFiniteNumber(url, "page");
47537
+ switch (anchorType) {
47538
+ case "page":
47539
+ if (page !== null) reference2.anchor = { type: anchorType, page };
47540
+ break;
47541
+ case "page_range": {
47542
+ const startPage = getFiniteNumber(url, "start_page");
47543
+ const endPage = getFiniteNumber(url, "end_page");
47544
+ if (startPage !== null && endPage !== null) {
47545
+ reference2.anchor = { type: anchorType, startPage, endPage };
47546
+ }
47547
+ break;
47548
+ }
47549
+ case "page_rect": {
47550
+ const x = getFiniteNumber(url, "x");
47551
+ const y = getFiniteNumber(url, "y");
47552
+ const width = getFiniteNumber(url, "width");
47553
+ const height = getFiniteNumber(url, "height");
47554
+ if (page !== null && x !== null && y !== null && width !== null && height !== null) {
47555
+ const unit = url.searchParams.get("unit");
47556
+ reference2.anchor = {
47557
+ type: anchorType,
47558
+ page,
47559
+ x,
47560
+ y,
47561
+ width,
47562
+ height,
47563
+ ...unit === "percent" || unit === "point" ? { unit } : {}
47564
+ };
47565
+ }
47566
+ break;
47567
+ }
47568
+ case "page_text": {
47569
+ const text2 = url.searchParams.get("text");
47570
+ if (page !== null && text2) reference2.anchor = { type: anchorType, page, text: text2 };
47571
+ break;
47572
+ }
47573
+ }
47574
+ const excerpt = url.searchParams.get("excerpt");
47575
+ if (excerpt) reference2.meta = { excerpt };
47576
+ return reference2;
47577
+ };
47524
47578
  const normalizeAssetType = (value) => {
47525
47579
  if (!value) {
47526
47580
  return null;
@@ -47609,7 +47663,8 @@ const parseAthenaCitationLink = ({
47609
47663
  url,
47610
47664
  assetId,
47611
47665
  assetIds,
47612
- assetType: normalizeAssetType(url.searchParams.get("asset_type") ?? url.searchParams.get("type"))
47666
+ assetType: normalizeAssetType(url.searchParams.get("asset_type") ?? url.searchParams.get("type")),
47667
+ reference: parseCitationReference({ url, assetId })
47613
47668
  };
47614
47669
  };
47615
47670
  const isAthenaCitationUrl = ({
@@ -56278,6 +56333,8 @@ function isAthenaAssetCitationClickEvent(value) {
56278
56333
  function isAthenaAssetCitationActionEvent(value) {
56279
56334
  return typeof value === "object" && value !== null && "type" in value && value.type === ATHENA_ASSET_CITATION_ACTION_MESSAGE && "version" in value && value.version === 1 && "action" in value && value.action === "open-in-spaces" && "reference" in value && typeof value.reference === "object" && value.reference !== null && "id" in value.reference && typeof value.reference.id === "string";
56280
56335
  }
56336
+ const DEFAULT_ASSET_EMBED_READ_ONLY = false;
56337
+ const DEFAULT_ASSET_EMBED_DISPLAY_MODE = "full";
56281
56338
  function buildAssetEmbedRequestBody({
56282
56339
  assetId,
56283
56340
  readOnly,
@@ -56453,6 +56510,9 @@ function appendCitationReferenceParams({
56453
56510
  key: "height",
56454
56511
  value: "height" in anchor ? anchor.height : void 0
56455
56512
  });
56513
+ if ("unit" in anchor && (anchor.unit === "percent" || anchor.unit === "point")) {
56514
+ params.set("unit", anchor.unit);
56515
+ }
56456
56516
  break;
56457
56517
  case "page_text":
56458
56518
  params.set("anchor", anchor.type);
@@ -56511,9 +56571,9 @@ function useAssetEmbed(assetId, options = {
56511
56571
  backendUrl: ""
56512
56572
  }) {
56513
56573
  const {
56514
- readOnly = false,
56574
+ readOnly = DEFAULT_ASSET_EMBED_READ_ONLY,
56515
56575
  expiresInSeconds = 60 * 60 * 24 * 30,
56516
- displayMode = "minimal",
56576
+ displayMode = DEFAULT_ASSET_EMBED_DISPLAY_MODE,
56517
56577
  backendUrl,
56518
56578
  appUrl,
56519
56579
  apiKey,
@@ -56606,8 +56666,8 @@ const AUTH_SYNC_INTERVAL_MS = 6e4;
56606
56666
  const AthenaAssetEmbed = ({
56607
56667
  assetId,
56608
56668
  reference: reference2,
56609
- displayMode = "full",
56610
- readOnly = true,
56669
+ displayMode = DEFAULT_ASSET_EMBED_DISPLAY_MODE,
56670
+ readOnly = DEFAULT_ASSET_EMBED_READ_ONLY,
56611
56671
  expiresInSeconds,
56612
56672
  citationBehavior,
56613
56673
  onCitationClick,