@apiboost/omnispec 1.1.0-next.5 → 1.1.0-next.7

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 (67) hide show
  1. package/README.md +4 -0
  2. package/dist/cjs/asyncapi/index.js +4 -4
  3. package/dist/cjs/chunks/{AsyncApiSpec-B-RGmOUL.js → AsyncApiSpec-g7Htcn89.js} +264 -119
  4. package/dist/cjs/chunks/AsyncApiSpec-g7Htcn89.js.map +1 -0
  5. package/dist/cjs/chunks/{Collapsible-qjYtxwP0.js → Collapsible-2_XxRGv-.js} +15 -3
  6. package/dist/cjs/chunks/Collapsible-2_XxRGv-.js.map +1 -0
  7. package/dist/cjs/chunks/{ErrorBoundary-CezYgQDG.js → ErrorBoundary-DokoK3KD.js} +2 -2
  8. package/dist/cjs/chunks/{ErrorBoundary-CezYgQDG.js.map → ErrorBoundary-DokoK3KD.js.map} +1 -1
  9. package/dist/cjs/chunks/{OmniSpecRenderer-Bh-IQod3.js → OmniSpecRenderer-CNPtTBa-.js} +6 -6
  10. package/dist/cjs/chunks/{OmniSpecRenderer-Bh-IQod3.js.map → OmniSpecRenderer-CNPtTBa-.js.map} +1 -1
  11. package/dist/cjs/chunks/{OpenApiSpec-5V9E-wQH.js → OpenApiSpec-BiJMyHZw.js} +5 -5
  12. package/dist/cjs/chunks/{OpenApiSpec-5V9E-wQH.js.map → OpenApiSpec-BiJMyHZw.js.map} +1 -1
  13. package/dist/cjs/chunks/{OpenIdConnectManual-DXDG8bcp.js → OpenIdConnectManual-u1xHZG3n.js} +3 -3
  14. package/dist/cjs/chunks/{OpenIdConnectManual-DXDG8bcp.js.map → OpenIdConnectManual-u1xHZG3n.js.map} +1 -1
  15. package/dist/cjs/chunks/{useSpecDetector-BemsWW9u.js → useSpecDetector-CAauxHEE.js} +3 -24
  16. package/dist/cjs/chunks/useSpecDetector-CAauxHEE.js.map +1 -0
  17. package/dist/cjs/chunks/{useSpecFetcher-BAbHnXax.js → useSpecFetcher-CpXe_imr.js} +5 -2
  18. package/dist/{esm/chunks/useSpecFetcher-BvVfMuzf.js.map → cjs/chunks/useSpecFetcher-CpXe_imr.js.map} +1 -1
  19. package/dist/cjs/core/public.js +4 -4
  20. package/dist/cjs/index.js +8 -8
  21. package/dist/cjs/openapi/index.js +5 -5
  22. package/dist/cjs/wc/index.js +4 -4
  23. package/dist/esm/asyncapi/index.js +4 -4
  24. package/dist/esm/chunks/{AsyncApiSpec-C0tdvyEP.js → AsyncApiSpec-dPymWhNP.js} +265 -120
  25. package/dist/esm/chunks/AsyncApiSpec-dPymWhNP.js.map +1 -0
  26. package/dist/esm/chunks/{Collapsible-CPxS90KX.js → Collapsible-DJnJiyJI.js} +15 -3
  27. package/dist/esm/chunks/Collapsible-DJnJiyJI.js.map +1 -0
  28. package/dist/esm/chunks/{ErrorBoundary-9pDlZFfM.js → ErrorBoundary-Ba5GPfFd.js} +2 -2
  29. package/dist/esm/chunks/{ErrorBoundary-9pDlZFfM.js.map → ErrorBoundary-Ba5GPfFd.js.map} +1 -1
  30. package/dist/esm/chunks/{OmniSpecRenderer-DmXZtPRr.js → OmniSpecRenderer-DykIUIbY.js} +6 -6
  31. package/dist/esm/chunks/{OmniSpecRenderer-DmXZtPRr.js.map → OmniSpecRenderer-DykIUIbY.js.map} +1 -1
  32. package/dist/esm/chunks/{OpenApiSpec-CoPhPro1.js → OpenApiSpec-CFtR52Jv.js} +5 -5
  33. package/dist/esm/chunks/{OpenApiSpec-CoPhPro1.js.map → OpenApiSpec-CFtR52Jv.js.map} +1 -1
  34. package/dist/esm/chunks/{OpenIdConnectManual-DhrAcSCa.js → OpenIdConnectManual-Cqh9kU1R.js} +3 -3
  35. package/dist/esm/chunks/{OpenIdConnectManual-DhrAcSCa.js.map → OpenIdConnectManual-Cqh9kU1R.js.map} +1 -1
  36. package/dist/esm/chunks/{useSpecDetector-BJBNbfN5.js → useSpecDetector-YPvOiNwd.js} +3 -24
  37. package/dist/esm/chunks/useSpecDetector-YPvOiNwd.js.map +1 -0
  38. package/dist/esm/chunks/{useSpecFetcher-BvVfMuzf.js → useSpecFetcher-DRDJ1CzD.js} +5 -2
  39. package/dist/{cjs/chunks/useSpecFetcher-BAbHnXax.js.map → esm/chunks/useSpecFetcher-DRDJ1CzD.js.map} +1 -1
  40. package/dist/esm/core/public.js +4 -4
  41. package/dist/esm/index.js +8 -8
  42. package/dist/esm/openapi/index.js +5 -5
  43. package/dist/esm/wc/index.js +4 -4
  44. package/dist/types/asyncapi/AsyncApiSpec.d.ts.map +1 -1
  45. package/dist/types/asyncapi/components/ChannelDetail.d.ts +7 -1
  46. package/dist/types/asyncapi/components/ChannelDetail.d.ts.map +1 -1
  47. package/dist/types/asyncapi/components/ChannelReferenceDetail.d.ts +7 -1
  48. package/dist/types/asyncapi/components/ChannelReferenceDetail.d.ts.map +1 -1
  49. package/dist/types/asyncapi/components/ReplyMeta.d.ts +25 -0
  50. package/dist/types/asyncapi/components/ReplyMeta.d.ts.map +1 -0
  51. package/dist/types/asyncapi/components/TagChips.d.ts +6 -1
  52. package/dist/types/asyncapi/components/TagChips.d.ts.map +1 -1
  53. package/dist/types/asyncapi/components/channel-actions.d.ts +25 -0
  54. package/dist/types/asyncapi/components/channel-actions.d.ts.map +1 -0
  55. package/dist/types/asyncapi/parser/asyncapi-parser.d.ts.map +1 -1
  56. package/dist/types/core/components/Layout/DocLayout.d.ts.map +1 -1
  57. package/dist/types/core/components/common/UpgradePrompt.d.ts.map +1 -1
  58. package/dist/types/core/hooks/useHashScroll.d.ts.map +1 -1
  59. package/dist/wc/standalone.js +1 -1
  60. package/dist/wc/standalone.js.map +1 -1
  61. package/package.json +1 -1
  62. package/dist/cjs/chunks/AsyncApiSpec-B-RGmOUL.js.map +0 -1
  63. package/dist/cjs/chunks/Collapsible-qjYtxwP0.js.map +0 -1
  64. package/dist/cjs/chunks/useSpecDetector-BemsWW9u.js.map +0 -1
  65. package/dist/esm/chunks/AsyncApiSpec-C0tdvyEP.js.map +0 -1
  66. package/dist/esm/chunks/Collapsible-CPxS90KX.js.map +0 -1
  67. package/dist/esm/chunks/useSpecDetector-BJBNbfN5.js.map +0 -1
@@ -3,9 +3,9 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var React = require('react');
5
5
  var css = require('@emotion/css');
6
- var useSpecFetcher = require('./useSpecFetcher-BAbHnXax.js');
7
- var Collapsible = require('./Collapsible-qjYtxwP0.js');
8
- var ErrorBoundary = require('./ErrorBoundary-CezYgQDG.js');
6
+ var useSpecFetcher = require('./useSpecFetcher-CpXe_imr.js');
7
+ var Collapsible = require('./Collapsible-2_XxRGv-.js');
8
+ var ErrorBoundary = require('./ErrorBoundary-DokoK3KD.js');
9
9
  var refResolver = require('./ref-resolver-0A8GNRI3.js');
10
10
  require('@emotion/styled');
11
11
  require('./ssrf-guard-B6T2A7Ho.js');
@@ -51,6 +51,27 @@ function deriveAppliedTraitNames(traits, rawTraits) {
51
51
  return trait.name ?? trait.title ?? `trait ${i + 1}`;
52
52
  });
53
53
  }
54
+ function resolveLocalPointer(root, ref) {
55
+ if (!ref.startsWith("#/")) return void 0;
56
+ let cur = root;
57
+ for (const seg of ref.slice(2).split("/")) {
58
+ if (cur === null || typeof cur !== "object") return void 0;
59
+ cur = cur[refResolver.decodeJsonPointerSegment(seg)];
60
+ }
61
+ return cur;
62
+ }
63
+ function rawMessageTraits(rawMsg, rawApi) {
64
+ let msg = rawMsg;
65
+ const seen = /* @__PURE__ */ new Set();
66
+ while (msg && typeof msg === "object" && typeof msg.$ref === "string") {
67
+ const ref = msg.$ref;
68
+ if (seen.has(ref)) return void 0;
69
+ seen.add(ref);
70
+ msg = resolveLocalPointer(rawApi, ref);
71
+ }
72
+ if (!msg || typeof msg !== "object") return void 0;
73
+ return msg.traits;
74
+ }
54
75
  function applyMessageTraits(msg, isV3) {
55
76
  if (!msg.traits || msg.traits.length === 0) return msg;
56
77
  if (isV3) {
@@ -93,10 +114,12 @@ async function parseAsyncApiSpec(specInput) {
93
114
  const servers = extractServers(api, raw);
94
115
  const rawApi = raw;
95
116
  const defaultContentType = api.defaultContentType;
96
- const channels = isV3 ? extractChannelsV3(api, rawApi, defaultContentType) : extractChannelsV2(api, defaultContentType);
117
+ const channels = isV3 ? extractChannelsV3(api, rawApi, defaultContentType) : extractChannelsV2(api, rawApi, defaultContentType);
97
118
  const components = extractComponents(api, rawApi, isV3, defaultContentType);
98
119
  const root = api;
99
- const tags = api.tags?.map((tag) => {
120
+ const rootTags = isV3 ? api.info.tags ?? api.tags : api.tags;
121
+ const rootExternalDocs = isV3 ? api.info.externalDocs ?? api.externalDocs : api.externalDocs;
122
+ const tags = rootTags?.map((tag) => {
100
123
  const raw2 = tag;
101
124
  return {
102
125
  name: tag.name,
@@ -115,7 +138,7 @@ async function parseAsyncApiSpec(specInput) {
115
138
  components,
116
139
  tags,
117
140
  tagGroups: root["x-tagGroups"],
118
- externalDocs: api.externalDocs,
141
+ externalDocs: rootExternalDocs,
119
142
  contact: api.info.contact,
120
143
  license: api.info.license,
121
144
  termsOfService: api.info.termsOfService,
@@ -145,15 +168,17 @@ function extractServers(api, rawApi) {
145
168
  const rawServers = !Array.isArray(rawApi.servers) && rawApi.servers || {};
146
169
  return Object.entries(api.servers).map(([name, s]) => toServer(s, name, rawServers[name]?.security));
147
170
  }
148
- function extractChannelsV2(api, defaultContentType) {
171
+ function extractChannelsV2(api, rawApi, defaultContentType) {
149
172
  if (!api.channels) return [];
173
+ const rawChannels = rawApi.channels ?? {};
150
174
  return Object.entries(api.channels).map(([channelName, ch]) => {
151
175
  const operations = [];
176
+ const rawCh = rawChannels[channelName];
152
177
  if (ch.publish) {
153
- operations.push(convertOperationV2("publish", ch.publish, defaultContentType));
178
+ operations.push(convertOperationV2("publish", ch.publish, rawCh?.publish, rawApi, defaultContentType));
154
179
  }
155
180
  if (ch.subscribe) {
156
- operations.push(convertOperationV2("subscribe", ch.subscribe, defaultContentType));
181
+ operations.push(convertOperationV2("subscribe", ch.subscribe, rawCh?.subscribe, rawApi, defaultContentType));
157
182
  }
158
183
  const raw = ch;
159
184
  return {
@@ -168,16 +193,20 @@ function extractChannelsV2(api, defaultContentType) {
168
193
  };
169
194
  });
170
195
  }
171
- function convertOperationV2(action, rawOp, defaultContentType) {
196
+ function convertOperationV2(action, rawOp, rawOperation, rawApi, defaultContentType) {
172
197
  const op = applyOperationTraits(rawOp, false);
173
198
  const messages = [];
174
199
  if (op.message) {
200
+ const rawMessage = rawOperation?.message;
175
201
  if ("oneOf" in op.message) {
176
- for (const m of op.message.oneOf) {
177
- messages.push(convertMessage(m, false, defaultContentType));
178
- }
202
+ op.message.oneOf.forEach((m, i) => {
203
+ const rawOneOf = rawMessage?.oneOf;
204
+ messages.push(convertMessage(m, false, defaultContentType, rawMessageTraits(rawOneOf?.[i], rawApi)));
205
+ });
179
206
  } else {
180
- messages.push(convertMessage(op.message, false, defaultContentType));
207
+ messages.push(
208
+ convertMessage(op.message, false, defaultContentType, rawMessageTraits(rawMessage, rawApi))
209
+ );
181
210
  }
182
211
  }
183
212
  const raw = op;
@@ -244,21 +273,26 @@ function extractChannelsV3(api, rawApi, defaultContentType) {
244
273
  const op = applyOperationTraits(resolvedOp, true);
245
274
  const rawOp = rawApi.operations?.[opKey];
246
275
  const channelName = resolveChannelName(rawOp?.channel, op.channel, addressToName);
247
- const collectMessages = (list) => {
276
+ const collectMessages = (list, rawList) => {
248
277
  const out = [];
249
- for (const msg of list ?? []) {
250
- if (msg && typeof msg === "object" && "$ref" in msg) continue;
251
- out.push(convertMessage(msg, true, defaultContentType));
252
- }
278
+ (list ?? []).forEach((msg, i) => {
279
+ if (msg && typeof msg === "object" && "$ref" in msg) return;
280
+ out.push(convertMessage(msg, true, defaultContentType, rawMessageTraits(rawList?.[i], rawApi)));
281
+ });
253
282
  return out;
254
283
  };
255
- let messages = collectMessages(op.messages);
284
+ let messages = collectMessages(op.messages, rawOp?.messages);
256
285
  if (messages.length === 0 && channelName && api.channels?.[channelName]?.messages) {
286
+ const rawChannelMessages = rawApi.channels?.[channelName]?.messages ?? {};
257
287
  messages = collectMessages(
258
- Object.values(api.channels[channelName].messages)
288
+ Object.values(api.channels[channelName].messages),
289
+ Object.values(rawChannelMessages)
259
290
  );
260
291
  }
261
- const replyMessages = collectMessages(op.reply?.messages);
292
+ const replyMessages = collectMessages(
293
+ op.reply?.messages,
294
+ rawOp?.reply?.messages
295
+ );
262
296
  const rawReplyChannel = rawOp?.reply?.channel;
263
297
  const replyChannelName = resolveChannelName(
264
298
  rawReplyChannel,
@@ -427,7 +461,7 @@ function ExternalLink({ href, children, label, className }) {
427
461
  target: "_blank",
428
462
  rel: "noopener noreferrer",
429
463
  "aria-label": `${label}, opens in new tab`,
430
- className: css.cx(linkStyle$1, className),
464
+ className: css.cx(linkStyle$2, className),
431
465
  children: [
432
466
  children,
433
467
  /* @__PURE__ */ jsxRuntime.jsx(useSpecFetcher.Icon, { name: "external-link", size: "0.875em" })
@@ -435,7 +469,7 @@ function ExternalLink({ href, children, label, className }) {
435
469
  }
436
470
  );
437
471
  }
438
- const linkStyle$1 = css.css({
472
+ const linkStyle$2 = css.css({
439
473
  display: "inline-flex",
440
474
  alignItems: "center",
441
475
  gap: "0.25rem",
@@ -489,7 +523,7 @@ const metaStyle = css.css({
489
523
  color: "var(--omnispec-fg-secondary)",
490
524
  marginTop: "0.25rem"
491
525
  });
492
- const linkStyle = css.css({
526
+ const linkStyle$1 = css.css({
493
527
  color: "var(--omnispec-fg-link)",
494
528
  textDecoration: "none",
495
529
  "&:hover": {
@@ -515,7 +549,7 @@ function AsyncOverview({ spec }) {
515
549
  ] }),
516
550
  spec.contact.email && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
517
551
  " <",
518
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: `mailto:${spec.contact.email}`, className: linkStyle, children: spec.contact.email }),
552
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: `mailto:${spec.contact.email}`, className: linkStyle$1, children: spec.contact.email }),
519
553
  ">"
520
554
  ] }),
521
555
  spec.contact.url && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
@@ -675,9 +709,9 @@ function FieldRows({
675
709
  verbatim = false
676
710
  }) {
677
711
  if (fields.length === 0) return null;
678
- return /* @__PURE__ */ jsxRuntime.jsx("dl", { className: listStyle$1, children: fields.map(([field, value]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rowStyle$1, children: [
712
+ return /* @__PURE__ */ jsxRuntime.jsx("dl", { className: listStyle$1, children: fields.map(([field, value]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rowStyle$2, children: [
679
713
  /* @__PURE__ */ jsxRuntime.jsx("dt", { className: nameStyle$1, children: verbatim ? field : humanizeField(field) }),
680
- /* @__PURE__ */ jsxRuntime.jsx("dd", { className: valueStyle, children: renderValue(value, verbatim) })
714
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: valueStyle$1, children: renderValue(value, verbatim) })
681
715
  ] }, field)) });
682
716
  }
683
717
  const listStyle$1 = css.css({
@@ -687,13 +721,13 @@ const listStyle$1 = css.css({
687
721
  margin: "0.25rem 0 0",
688
722
  minWidth: 0
689
723
  });
690
- const rowStyle$1 = css.css({ display: "contents" });
724
+ const rowStyle$2 = css.css({ display: "contents" });
691
725
  const nameStyle$1 = css.css({
692
726
  fontSize: "var(--omnispec-font-size-xs)",
693
727
  fontWeight: 600,
694
728
  color: "var(--omnispec-fg-secondary)"
695
729
  });
696
- const valueStyle = css.css({
730
+ const valueStyle$1 = css.css({
697
731
  fontSize: "var(--omnispec-font-size-xs)",
698
732
  color: "var(--omnispec-fg-primary)",
699
733
  margin: 0,
@@ -838,8 +872,8 @@ const emptyStyle = css.css({
838
872
 
839
873
  function SecurityRequirementBadges({ requirements, label = "Security" }) {
840
874
  if (!requirements || requirements.length === 0) return null;
841
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rowStyle, children: [
842
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: labelStyle, children: label }),
875
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rowStyle$1, children: [
876
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: labelStyle$1, children: label }),
843
877
  requirements.map((alternative, altIndex) => {
844
878
  const chips = alternative.map((scheme) => /* @__PURE__ */ jsxRuntime.jsxs("a", { href: `#security-${scheme.name}`, className: badgeStyle, children: [
845
879
  /* @__PURE__ */ jsxRuntime.jsx(useSpecFetcher.Icon, { name: "lock", size: "0.625rem", strokeWidth: 2.5 }),
@@ -856,7 +890,7 @@ function SecurityRequirementBadges({ requirements, label = "Security" }) {
856
890
  })
857
891
  ] });
858
892
  }
859
- const rowStyle = css.css({
893
+ const rowStyle$1 = css.css({
860
894
  display: "flex",
861
895
  alignItems: "center",
862
896
  gap: "0.375rem",
@@ -872,7 +906,7 @@ const orGroupStyle = css.css({
872
906
  gap: "0.375rem",
873
907
  whiteSpace: "nowrap"
874
908
  });
875
- const labelStyle = css.css({
909
+ const labelStyle$1 = css.css({
876
910
  fontSize: "var(--omnispec-font-size-xxs)",
877
911
  lineHeight: 1.5,
878
912
  fontWeight: 600,
@@ -1068,7 +1102,7 @@ function ServerList({ servers }) {
1068
1102
  ] });
1069
1103
  }
1070
1104
 
1071
- function TagChips({ tags, onTagClick }) {
1105
+ function TagChips({ tags, onTagClick, activeTag }) {
1072
1106
  if (!tags || tags.length === 0) return null;
1073
1107
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: tagChipsStyle$1, children: tags.map((tag) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: tagItemStyle, children: [
1074
1108
  onTagClick ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -1077,6 +1111,7 @@ function TagChips({ tags, onTagClick }) {
1077
1111
  type: "button",
1078
1112
  className: tagChipButtonStyle$1,
1079
1113
  title: tag.description,
1114
+ "aria-pressed": tag.name === activeTag,
1080
1115
  onClick: () => onTagClick(tag.name),
1081
1116
  children: tag.name
1082
1117
  }
@@ -1335,22 +1370,94 @@ const unresolvedRefCodeStyle = css.css({
1335
1370
  fontSize: "var(--omnispec-font-size-xs)"
1336
1371
  });
1337
1372
 
1338
- const actionLabels$1 = {
1373
+ const actionLabels = {
1339
1374
  publish: "PUB",
1340
1375
  subscribe: "SUB",
1341
1376
  send: "SEND",
1342
1377
  receive: "RECV"
1343
1378
  };
1344
- const actionColors$1 = {
1379
+ const actionColors = {
1345
1380
  publish: "var(--omnispec-color-publish)",
1346
1381
  subscribe: "var(--omnispec-color-subscribe)",
1347
1382
  send: "var(--omnispec-color-publish)",
1348
1383
  receive: "var(--omnispec-color-subscribe)"
1349
1384
  };
1350
- function ChannelDetail({ channel, id, expandAll, expandGeneration, onTagClick }) {
1351
- const primaryAction = channel.operations[0]?.action;
1352
- const primaryLabel = actionLabels$1[primaryAction] ?? primaryAction?.toUpperCase() ?? "";
1353
- const primaryColor = actionColors$1[primaryAction] ?? "var(--omnispec-fg-muted)";
1385
+ function channelActionBadge(channel) {
1386
+ const distinct = [...new Set(channel.operations.map((op) => op.action))];
1387
+ const label = distinct.map((a) => actionLabels[a] ?? a.toUpperCase()).join(" / ");
1388
+ const color = distinct.length === 1 ? actionColors[distinct[0]] ?? "var(--omnispec-fg-muted)" : "var(--omnispec-color-primary)";
1389
+ return { label, color };
1390
+ }
1391
+
1392
+ function ReplyMeta({
1393
+ reply,
1394
+ channelHref,
1395
+ onChannelNavigate
1396
+ }) {
1397
+ const hasAddress = reply.address && (reply.address.value || reply.address.location || reply.address.description);
1398
+ const replyHref = reply.channelName ? channelHref?.(reply.channelName) : void 0;
1399
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1400
+ reply.channelName && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rowStyle, children: [
1401
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: labelStyle, children: "channel" }),
1402
+ replyHref ? /* @__PURE__ */ jsxRuntime.jsx(
1403
+ "a",
1404
+ {
1405
+ href: replyHref,
1406
+ className: linkStyle,
1407
+ onClick: onChannelNavigate ? (e) => {
1408
+ e.preventDefault();
1409
+ onChannelNavigate(reply.channelName);
1410
+ } : void 0,
1411
+ children: reply.channelName
1412
+ }
1413
+ ) : /* @__PURE__ */ jsxRuntime.jsx("code", { className: valueStyle, children: reply.channelName })
1414
+ ] }),
1415
+ hasAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rowStyle, children: [
1416
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: labelStyle, children: "address" }),
1417
+ reply.address?.value && /* @__PURE__ */ jsxRuntime.jsx("code", { className: valueStyle, children: reply.address.value }),
1418
+ reply.address?.location && /* @__PURE__ */ jsxRuntime.jsx("code", { className: valueStyle, children: reply.address.location }),
1419
+ reply.address?.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: descStyle$2, children: reply.address.description })
1420
+ ] })
1421
+ ] });
1422
+ }
1423
+ const rowStyle = css.css({
1424
+ display: "flex",
1425
+ alignItems: "center",
1426
+ gap: "0.5rem",
1427
+ flexWrap: "wrap",
1428
+ marginBottom: "0.5rem"
1429
+ });
1430
+ const labelStyle = css.css({
1431
+ fontSize: "var(--omnispec-font-size-xs)",
1432
+ fontWeight: 700,
1433
+ color: "var(--omnispec-fg-primary)",
1434
+ fontFamily: "var(--omnispec-font-mono)"
1435
+ });
1436
+ const valueStyle = css.css({
1437
+ fontFamily: "var(--omnispec-font-mono)",
1438
+ fontSize: "var(--omnispec-font-size-xs)",
1439
+ color: "var(--omnispec-fg-code)",
1440
+ backgroundColor: "var(--omnispec-bg-tertiary)",
1441
+ padding: "0.0625rem 0.375rem",
1442
+ borderRadius: "0.1875rem"
1443
+ });
1444
+ const linkStyle = css.css({
1445
+ fontFamily: "var(--omnispec-font-mono)",
1446
+ fontSize: "var(--omnispec-font-size-xs)",
1447
+ color: "var(--omnispec-color-primary)",
1448
+ backgroundColor: "var(--omnispec-bg-tertiary)",
1449
+ padding: "0.0625rem 0.375rem",
1450
+ borderRadius: "0.1875rem",
1451
+ textDecoration: "none",
1452
+ "&:hover": { textDecoration: "underline" }
1453
+ });
1454
+ const descStyle$2 = css.css({
1455
+ fontSize: "var(--omnispec-font-size-xs)",
1456
+ color: "var(--omnispec-fg-secondary)"
1457
+ });
1458
+
1459
+ function ChannelDetail({ channel, id, expandAll, expandGeneration, onTagClick, activeTag, channelHref, onChannelNavigate }) {
1460
+ const headerBadge = channelActionBadge(channel);
1354
1461
  return /* @__PURE__ */ jsxRuntime.jsxs(
1355
1462
  Collapsible.ExpandableCard,
1356
1463
  {
@@ -1360,10 +1467,10 @@ function ChannelDetail({ channel, id, expandAll, expandGeneration, onTagClick })
1360
1467
  expandAll,
1361
1468
  expandGeneration,
1362
1469
  children: [
1363
- /* @__PURE__ */ jsxRuntime.jsx(Collapsible.MethodBar, { label: primaryLabel, path: channel.address, color: primaryColor }),
1470
+ /* @__PURE__ */ jsxRuntime.jsx(Collapsible.MethodBar, { label: headerBadge.label, path: channel.address, color: headerBadge.color }),
1364
1471
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: bodyStyle, children: [
1365
1472
  channel.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: sectionStyle$1, children: /* @__PURE__ */ jsxRuntime.jsx(Collapsible.MarkdownRenderer, { content: channel.description }) }),
1366
- channel.tags && channel.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(TagChips, { tags: channel.tags, onTagClick }),
1473
+ channel.tags && channel.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(TagChips, { tags: channel.tags, onTagClick, activeTag }),
1367
1474
  channel.externalDocs && /* @__PURE__ */ jsxRuntime.jsx("div", { className: sectionStyle$1, children: /* @__PURE__ */ jsxRuntime.jsx(ExternalDocsLink, { externalDocs: channel.externalDocs, context: channel.address }) }),
1368
1475
  channel.parameters && Object.keys(channel.parameters).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: sectionStyle$1, children: [
1369
1476
  /* @__PURE__ */ jsxRuntime.jsx("h4", { className: sectionTitleStyle$1, children: "Parameters" }),
@@ -1398,9 +1505,9 @@ function ChannelDetail({ channel, id, expandAll, expandGeneration, onTagClick })
1398
1505
  "span",
1399
1506
  {
1400
1507
  className: css.cx(actionBadgeBase$1, css.css({
1401
- backgroundColor: actionColors$1[op.action] ?? "var(--omnispec-fg-muted)"
1508
+ backgroundColor: actionColors[op.action] ?? "var(--omnispec-fg-muted)"
1402
1509
  })),
1403
- children: actionLabels$1[op.action] ?? op.action.toUpperCase()
1510
+ children: actionLabels[op.action] ?? op.action.toUpperCase()
1404
1511
  }
1405
1512
  ),
1406
1513
  op.operationId && /* @__PURE__ */ jsxRuntime.jsx("span", { className: opIdStyle$1, children: op.operationId }),
@@ -1408,7 +1515,7 @@ function ChannelDetail({ channel, id, expandAll, expandGeneration, onTagClick })
1408
1515
  ] }),
1409
1516
  op.summary && /* @__PURE__ */ jsxRuntime.jsx("span", { className: opSummaryStyle$1, children: op.summary })
1410
1517
  ] }),
1411
- op.tags && op.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(TagChips, { tags: op.tags, onTagClick }),
1518
+ op.tags && op.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(TagChips, { tags: op.tags, onTagClick, activeTag }),
1412
1519
  op.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: sectionStyle$1, children: /* @__PURE__ */ jsxRuntime.jsx(Collapsible.MarkdownRenderer, { content: op.description }) }),
1413
1520
  op.externalDocs && /* @__PURE__ */ jsxRuntime.jsx("div", { className: opExternalDocsStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
1414
1521
  ExternalDocsLink,
@@ -1421,16 +1528,7 @@ function ChannelDetail({ channel, id, expandAll, expandGeneration, onTagClick })
1421
1528
  /* @__PURE__ */ jsxRuntime.jsx(OperationMessages, { operation: op, idx }),
1422
1529
  op.reply && (op.reply.messages.length > 0 || op.reply.address || op.reply.channelName) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: replyStyle$1, children: [
1423
1530
  /* @__PURE__ */ jsxRuntime.jsx("h4", { className: replyTitleStyle, children: "Reply" }),
1424
- op.reply.channelName && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: replyMetaRowStyle, children: [
1425
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: replyMetaLabelStyle, children: "channel" }),
1426
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: replyMetaValueStyle, children: op.reply.channelName })
1427
- ] }),
1428
- op.reply.address && (op.reply.address.value || op.reply.address.location || op.reply.address.description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: replyMetaRowStyle, children: [
1429
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: replyMetaLabelStyle, children: "address" }),
1430
- op.reply.address.value && /* @__PURE__ */ jsxRuntime.jsx("code", { className: replyMetaValueStyle, children: op.reply.address.value }),
1431
- op.reply.address.location && /* @__PURE__ */ jsxRuntime.jsx("code", { className: replyMetaValueStyle, children: op.reply.address.location }),
1432
- op.reply.address.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: replyMetaDescStyle, children: op.reply.address.description })
1433
- ] }),
1531
+ /* @__PURE__ */ jsxRuntime.jsx(ReplyMeta, { reply: op.reply, channelHref, onChannelNavigate }),
1434
1532
  op.reply.messages.map((replyMsg, i) => /* @__PURE__ */ jsxRuntime.jsx(MessageView, { message: replyMsg, idx: `${idx}-reply-${i}` }, i))
1435
1533
  ] }),
1436
1534
  /* @__PURE__ */ jsxRuntime.jsx(BindingsSection, { bindings: op.bindings, title: "Operation Bindings" })
@@ -1676,48 +1774,9 @@ const replyTitleStyle = css.css({
1676
1774
  color: "var(--omnispec-fg-primary)",
1677
1775
  letterSpacing: "0.02em"
1678
1776
  });
1679
- const replyMetaRowStyle = css.css({
1680
- display: "flex",
1681
- alignItems: "center",
1682
- gap: "0.5rem",
1683
- flexWrap: "wrap",
1684
- marginBottom: "0.5rem"
1685
- });
1686
- const replyMetaLabelStyle = css.css({
1687
- fontSize: "var(--omnispec-font-size-xs)",
1688
- fontWeight: 700,
1689
- color: "var(--omnispec-fg-primary)",
1690
- fontFamily: "var(--omnispec-font-mono)"
1691
- });
1692
- const replyMetaValueStyle = css.css({
1693
- fontFamily: "var(--omnispec-font-mono)",
1694
- fontSize: "var(--omnispec-font-size-xs)",
1695
- color: "var(--omnispec-fg-code)",
1696
- backgroundColor: "var(--omnispec-bg-tertiary)",
1697
- padding: "1px 0.375rem",
1698
- borderRadius: "0.1875rem"
1699
- });
1700
- const replyMetaDescStyle = css.css({
1701
- fontSize: "var(--omnispec-font-size-xs)",
1702
- color: "var(--omnispec-fg-secondary)"
1703
- });
1704
1777
 
1705
- const actionLabels = {
1706
- publish: "PUB",
1707
- subscribe: "SUB",
1708
- send: "SEND",
1709
- receive: "RECV"
1710
- };
1711
- const actionColors = {
1712
- publish: "var(--omnispec-color-publish)",
1713
- subscribe: "var(--omnispec-color-subscribe)",
1714
- send: "var(--omnispec-color-publish)",
1715
- receive: "var(--omnispec-color-subscribe)"
1716
- };
1717
- function ChannelReferenceDetail({ channel, id, expandAll, expandGeneration, onTagClick }) {
1718
- const primaryAction = channel.operations[0]?.action;
1719
- const primaryLabel = actionLabels[primaryAction] ?? primaryAction?.toUpperCase() ?? "";
1720
- const primaryColor = actionColors[primaryAction] ?? "var(--omnispec-fg-muted)";
1778
+ function ChannelReferenceDetail({ channel, id, expandAll, expandGeneration, onTagClick, activeTag, channelHref, onChannelNavigate }) {
1779
+ const headerBadge = channelActionBadge(channel);
1721
1780
  return /* @__PURE__ */ jsxRuntime.jsxs(
1722
1781
  Collapsible.ExpandableCard,
1723
1782
  {
@@ -1727,23 +1786,32 @@ function ChannelReferenceDetail({ channel, id, expandAll, expandGeneration, onTa
1727
1786
  expandAll,
1728
1787
  expandGeneration,
1729
1788
  children: [
1730
- /* @__PURE__ */ jsxRuntime.jsx(Collapsible.MethodBar, { label: primaryLabel, path: channel.address, color: primaryColor }),
1789
+ /* @__PURE__ */ jsxRuntime.jsx(Collapsible.MethodBar, { label: headerBadge.label, path: channel.address, color: headerBadge.color }),
1731
1790
  channel.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: channelMetaStyle, children: /* @__PURE__ */ jsxRuntime.jsx(Collapsible.MarkdownRenderer, { content: channel.description }) }),
1732
1791
  channel.externalDocs && /* @__PURE__ */ jsxRuntime.jsx("div", { className: channelMetaStyle, children: /* @__PURE__ */ jsxRuntime.jsx(ExternalDocsLink, { externalDocs: channel.externalDocs, context: channel.address }) }),
1733
1792
  channel.operations.map((op, idx) => /* @__PURE__ */ jsxRuntime.jsx("div", { id: id ? `${id}-op-${idx}` : void 0, className: operationWrapStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
1734
1793
  Collapsible.ReferenceLayout,
1735
1794
  {
1736
1795
  operationId: op.operationId ?? `${channel.name}-op-${idx}`,
1737
- schema: /* @__PURE__ */ jsxRuntime.jsx(
1796
+ schema: /* @__PURE__ */ jsxRuntime.jsx("div", { className: refMobilePadStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
1738
1797
  OperationSchemaColumn,
1739
1798
  {
1740
1799
  channel,
1741
1800
  operation: op,
1742
- onTagClick
1801
+ onTagClick,
1802
+ activeTag
1803
+ }
1804
+ ) }),
1805
+ samples: /* @__PURE__ */ jsxRuntime.jsx("div", { className: refMobilePadStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
1806
+ OperationSamplesColumn,
1807
+ {
1808
+ operation: op,
1809
+ idx,
1810
+ channelHref,
1811
+ onChannelNavigate
1743
1812
  }
1744
- ),
1745
- samples: /* @__PURE__ */ jsxRuntime.jsx(OperationSamplesColumn, { operation: op, idx }),
1746
- tryIt: /* @__PURE__ */ jsxRuntime.jsx("div", { className: tryItNaStyle, children: "Interactive testing is not available for AsyncAPI protocols." })
1813
+ ) }),
1814
+ tryIt: /* @__PURE__ */ jsxRuntime.jsx("div", { className: css.cx(refMobilePadStyle, tryItNaStyle), children: "Interactive testing is not available for AsyncAPI protocols." })
1747
1815
  }
1748
1816
  ) }, idx))
1749
1817
  ]
@@ -1753,7 +1821,8 @@ function ChannelReferenceDetail({ channel, id, expandAll, expandGeneration, onTa
1753
1821
  function OperationSchemaColumn({
1754
1822
  channel,
1755
1823
  operation,
1756
- onTagClick
1824
+ onTagClick,
1825
+ activeTag
1757
1826
  }) {
1758
1827
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1759
1828
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: opHeaderStyle, children: [
@@ -1777,6 +1846,7 @@ function OperationSchemaColumn({
1777
1846
  type: "button",
1778
1847
  className: tagChipButtonStyle,
1779
1848
  title: tag.description,
1849
+ "aria-pressed": tag.name === activeTag,
1780
1850
  onClick: () => onTagClick(tag.name),
1781
1851
  children: tag.name
1782
1852
  },
@@ -1821,10 +1891,11 @@ function OperationSchemaColumn({
1821
1891
  /* @__PURE__ */ jsxRuntime.jsx(BindingsSection, { bindings: channel.bindings, title: "Channel Bindings" })
1822
1892
  ] });
1823
1893
  }
1824
- function OperationSamplesColumn({ operation, idx }) {
1894
+ function OperationSamplesColumn({ operation, idx, channelHref, onChannelNavigate }) {
1825
1895
  const messages = operation.messages ?? [];
1826
- const replyMessages = operation.reply?.messages ?? [];
1827
- if (messages.length === 0 && replyMessages.length === 0) {
1896
+ const reply = operation.reply;
1897
+ const hasReply = !!(reply && (reply.messages.length > 0 || reply.address || reply.channelName));
1898
+ if (messages.length === 0 && !hasReply) {
1828
1899
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: emptySamplesStyle, children: "No message payload is defined for this operation." });
1829
1900
  }
1830
1901
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: samplesColumnStyle, children: [
@@ -1839,9 +1910,10 @@ function OperationSamplesColumn({ operation, idx }) {
1839
1910
  message.contentType && /* @__PURE__ */ jsxRuntime.jsx("code", { className: contentTypeStyle$1, children: message.contentType }),
1840
1911
  /* @__PURE__ */ jsxRuntime.jsx(MessagePayload, { message, idx: `${idx}-msg-${i}` })
1841
1912
  ] }, i)),
1842
- replyMessages.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: replyStyle, children: [
1913
+ hasReply && reply && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: replyStyle, children: [
1843
1914
  /* @__PURE__ */ jsxRuntime.jsx("h4", { className: sectionTitleStyle, children: "Reply" }),
1844
- replyMessages.map((message, i) => /* @__PURE__ */ jsxRuntime.jsx(MessagePayload, { message, idx: `${idx}-reply-${i}` }, i))
1915
+ /* @__PURE__ */ jsxRuntime.jsx(ReplyMeta, { reply, channelHref, onChannelNavigate }),
1916
+ reply.messages.map((message, i) => /* @__PURE__ */ jsxRuntime.jsx(MessagePayload, { message, idx: `${idx}-reply-${i}` }, i))
1845
1917
  ] })
1846
1918
  ] });
1847
1919
  }
@@ -1851,6 +1923,9 @@ const channelMetaStyle = css.css({
1851
1923
  padding: "1rem 1.25rem 0"
1852
1924
  }
1853
1925
  });
1926
+ const refMobilePadStyle = css.css({
1927
+ [useSpecFetcher.mq.mobile]: { paddingInline: "1rem" }
1928
+ });
1854
1929
  const operationWrapStyle = css.css({
1855
1930
  borderTop: "1px solid var(--omnispec-border-color)"
1856
1931
  });
@@ -1918,7 +1993,9 @@ const paramConstraintsStyle = css.css({
1918
1993
  const opHeaderStyle = css.css({
1919
1994
  display: "flex",
1920
1995
  alignItems: "center",
1921
- gap: "0.5rem",
1996
+ flexWrap: "wrap",
1997
+ gap: "0.25rem 0.5rem",
1998
+ minWidth: 0,
1922
1999
  marginBottom: "0.5rem"
1923
2000
  });
1924
2001
  const actionBadgeBase = css.css({
@@ -1935,16 +2012,21 @@ const opIdStyle = css.css({
1935
2012
  fontSize: "var(--omnispec-font-size-sm)",
1936
2013
  fontWeight: 700,
1937
2014
  backgroundColor: "transparent",
1938
- padding: 0
2015
+ padding: 0,
2016
+ overflowWrap: "anywhere"
1939
2017
  });
1940
2018
  const opTitleStyle = css.css({
1941
2019
  fontSize: "var(--omnispec-font-size-sm)",
1942
2020
  fontWeight: 600,
1943
- color: "var(--omnispec-fg-primary)"
2021
+ color: "var(--omnispec-fg-primary)",
2022
+ overflowWrap: "anywhere"
1944
2023
  });
1945
2024
  const opSummaryStyle = css.css({
2025
+ flexBasis: "100%",
2026
+ minWidth: 0,
1946
2027
  fontSize: "var(--omnispec-font-size-sm)",
1947
- color: "var(--omnispec-fg-secondary)"
2028
+ color: "var(--omnispec-fg-secondary)",
2029
+ overflowWrap: "anywhere"
1948
2030
  });
1949
2031
  const messageTitleStyle = css.css({
1950
2032
  fontWeight: 400,
@@ -2394,17 +2476,39 @@ function AsyncApiSpec({
2394
2476
  setActiveTagFilter((prev) => {
2395
2477
  const next = prev === tagName ? null : tagName;
2396
2478
  setSearchQuery(next ?? "");
2479
+ writeTagParam(next);
2397
2480
  return next;
2398
2481
  });
2399
2482
  }, []);
2400
2483
  const handleSearch = React.useCallback((query) => {
2401
2484
  setSearchQuery(query);
2402
2485
  setActiveTagFilter(null);
2486
+ writeTagParam(null);
2403
2487
  }, []);
2404
2488
  const clearTagFilter = React.useCallback(() => {
2405
2489
  setActiveTagFilter(null);
2406
2490
  setSearchQuery("");
2491
+ writeTagParam(null);
2407
2492
  }, []);
2493
+ const availableTags = React.useMemo(() => {
2494
+ const names = /* @__PURE__ */ new Set();
2495
+ for (const tag of parsedSpec?.tags ?? []) names.add(tag.name);
2496
+ for (const ch of parsedSpec?.channels ?? []) {
2497
+ for (const tag of ch.tags ?? []) names.add(tag.name);
2498
+ for (const op of ch.operations) for (const t of op.tags ?? []) names.add(t.name);
2499
+ }
2500
+ return names;
2501
+ }, [parsedSpec]);
2502
+ const didInitFromUrl = React.useRef(false);
2503
+ React.useEffect(() => {
2504
+ if (didInitFromUrl.current || !parsedSpec) return;
2505
+ didInitFromUrl.current = true;
2506
+ const urlTag = readTagParam();
2507
+ if (urlTag && availableTags.has(urlTag)) {
2508
+ setActiveTagFilter(urlTag);
2509
+ setSearchQuery(urlTag);
2510
+ }
2511
+ }, [parsedSpec, availableTags]);
2408
2512
  React.useMemo(() => {
2409
2513
  if (parsedSpec && onSpecLoaded) {
2410
2514
  const major = parseInt(parsedSpec.specVersion.split(".")[0], 10);
@@ -2454,6 +2558,13 @@ function AsyncApiSpec({
2454
2558
  }
2455
2559
  return map;
2456
2560
  }, [filteredChannels, channelDomId]);
2561
+ const channelHref = React.useCallback(
2562
+ (channelName) => {
2563
+ const domId = channelDomId.get(channelName);
2564
+ return domId ? `#${domId}` : void 0;
2565
+ },
2566
+ [channelDomId]
2567
+ );
2457
2568
  const hasOperations = React.useMemo(
2458
2569
  () => filteredChannels.some((ch) => ch.operations.length > 0),
2459
2570
  [filteredChannels]
@@ -2538,6 +2649,10 @@ function AsyncApiSpec({
2538
2649
  }
2539
2650
  navigateTo(id);
2540
2651
  }, [navigateTo, opToCard]);
2652
+ const onChannelNavigate = React.useCallback((channelName) => {
2653
+ const domId = channelDomId.get(channelName);
2654
+ if (domId) navigateTo(domId);
2655
+ }, [channelDomId, navigateTo]);
2541
2656
  const navSectionIds = React.useMemo(() => Collapsible.flattenNavItemIds(navItems), [navItems]);
2542
2657
  const activeSection = Collapsible.useScrollSpy(navSectionIds);
2543
2658
  if (state.status === "loading") {
@@ -2563,7 +2678,7 @@ function AsyncApiSpec({
2563
2678
  /* @__PURE__ */ jsxRuntime.jsx(
2564
2679
  Collapsible.SearchBar,
2565
2680
  {
2566
- placeholder: "Filter channels...",
2681
+ placeholder: navGrouping === "operation" ? "Filter operations..." : "Filter channels...",
2567
2682
  onSearch: handleSearch,
2568
2683
  value: searchQuery
2569
2684
  }
@@ -2658,7 +2773,10 @@ function AsyncApiSpec({
2658
2773
  displayMode: resolvedDisplayMode,
2659
2774
  expandAll: allExpanded,
2660
2775
  expandGeneration,
2661
- onTagClick: handleTagFilter
2776
+ onTagClick: handleTagFilter,
2777
+ activeTag: activeTagFilter,
2778
+ channelHref,
2779
+ onChannelNavigate
2662
2780
  },
2663
2781
  `${group.id}-${channel.name}`
2664
2782
  ))
@@ -2670,7 +2788,10 @@ function AsyncApiSpec({
2670
2788
  displayMode: resolvedDisplayMode,
2671
2789
  expandAll: allExpanded,
2672
2790
  expandGeneration,
2673
- onTagClick: handleTagFilter
2791
+ onTagClick: handleTagFilter,
2792
+ activeTag: activeTagFilter,
2793
+ channelHref,
2794
+ onChannelNavigate
2674
2795
  },
2675
2796
  channel.name
2676
2797
  ))
@@ -2687,7 +2808,10 @@ function ChannelCard({
2687
2808
  displayMode,
2688
2809
  expandAll,
2689
2810
  expandGeneration,
2690
- onTagClick
2811
+ onTagClick,
2812
+ activeTag,
2813
+ channelHref,
2814
+ onChannelNavigate
2691
2815
  }) {
2692
2816
  const Renderer = displayMode === "reference" ? ChannelReferenceDetail : ChannelDetail;
2693
2817
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2697,10 +2821,31 @@ function ChannelCard({
2697
2821
  channel,
2698
2822
  expandAll,
2699
2823
  expandGeneration,
2700
- onTagClick
2824
+ onTagClick,
2825
+ activeTag,
2826
+ channelHref,
2827
+ onChannelNavigate
2701
2828
  }
2702
2829
  );
2703
2830
  }
2831
+ const TAG_PARAM = "omnispec-tag";
2832
+ function readTagParam() {
2833
+ if (typeof window === "undefined") return null;
2834
+ return new URLSearchParams(window.location.search).get(TAG_PARAM);
2835
+ }
2836
+ function writeTagParam(tag) {
2837
+ if (typeof window === "undefined") return;
2838
+ const params = new URLSearchParams(window.location.search);
2839
+ if (params.get(TAG_PARAM) === (tag ?? null)) return;
2840
+ if (tag) params.set(TAG_PARAM, tag);
2841
+ else params.delete(TAG_PARAM);
2842
+ const query = params.toString();
2843
+ window.history.replaceState(
2844
+ window.history.state,
2845
+ "",
2846
+ `${window.location.pathname}${query ? `?${query}` : ""}${window.location.hash}`
2847
+ );
2848
+ }
2704
2849
  function nestByTagGroups(groups, xTagGroups, toNav) {
2705
2850
  if (!xTagGroups?.length) return groups.map(toNav);
2706
2851
  const byTagName = /* @__PURE__ */ new Map();
@@ -2821,4 +2966,4 @@ const activeFilterClearStyle = css.css({
2821
2966
  });
2822
2967
 
2823
2968
  exports.AsyncApiSpec = AsyncApiSpec;
2824
- //# sourceMappingURL=AsyncApiSpec-B-RGmOUL.js.map
2969
+ //# sourceMappingURL=AsyncApiSpec-g7Htcn89.js.map