@feedlog-ai/webcomponents 0.0.42 → 0.0.44

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 (48) hide show
  1. package/README.md +6 -0
  2. package/dist/{esm/purify.es-B8AIqnOZ.js → cjs/browser-MBNPN4qV.js} +49 -3
  3. package/dist/cjs/feedlog-button_3.cjs.entry.js +6 -5
  4. package/dist/cjs/feedlog-issues-client.cjs.entry.js +48 -72
  5. package/dist/cjs/feedlog-issues.cjs.entry.js +1 -1
  6. package/dist/cjs/feedlog-toolkit.cjs.js +1 -1
  7. package/dist/cjs/loader.cjs.js +1 -1
  8. package/dist/collection/components/feedlog-issue/feedlog-issue.js +5 -4
  9. package/dist/collection/components/feedlog-issues/feedlog-issues.js +4 -4
  10. package/dist/collection/components/feedlog-issues-client/feedlog-issues-client.js +47 -26
  11. package/dist/collection/components/feedlog-issues-list/feedlog-issues-list.js +3 -3
  12. package/dist/collection/utils/markdown.js +2 -1
  13. package/dist/components/feedlog-badge.js +1 -1
  14. package/dist/components/feedlog-button.js +1 -1
  15. package/dist/components/feedlog-card.js +1 -1
  16. package/dist/components/feedlog-issue.js +1 -1
  17. package/dist/components/feedlog-issues-client.js +1 -1
  18. package/dist/components/feedlog-issues-list.js +1 -1
  19. package/dist/components/feedlog-issues.js +1 -1
  20. package/dist/components/{p-DLNSSGDc.js → p-B-jbJSEa.js} +1 -1
  21. package/dist/components/p-BWpmSn38.js +1 -0
  22. package/dist/components/{p-DzATWlAC.js → p-C-bUP9VO.js} +1 -1
  23. package/dist/components/{p-DMdb-G26.js → p-CIASvKvr.js} +1 -1
  24. package/dist/components/p-Du-VNLmx.js +2 -0
  25. package/dist/{cjs/purify.es-CfCgypMZ.js → esm/browser-BFRt9b48.js} +46 -5
  26. package/dist/esm/feedlog-button_3.entry.js +6 -5
  27. package/dist/esm/feedlog-issues-client.entry.js +47 -71
  28. package/dist/esm/feedlog-issues.entry.js +1 -1
  29. package/dist/esm/feedlog-toolkit.js +1 -1
  30. package/dist/esm/loader.js +1 -1
  31. package/dist/feedlog-toolkit/feedlog-toolkit.esm.js +1 -1
  32. package/dist/feedlog-toolkit/p-87583f75.entry.js +1 -0
  33. package/dist/feedlog-toolkit/{p-2901a753.entry.js → p-97d28b9d.entry.js} +1 -1
  34. package/dist/feedlog-toolkit/p-BFRt9b48.js +2 -0
  35. package/dist/feedlog-toolkit/{p-a7dcf9b6.entry.js → p-e8eb4cf5.entry.js} +1 -1
  36. package/dist/types/components/feedlog-issue/feedlog-issue.d.ts +2 -2
  37. package/dist/types/components/feedlog-issues/feedlog-issues.d.ts +2 -2
  38. package/dist/types/components/feedlog-issues-client/feedlog-issues-client.d.ts +4 -4
  39. package/dist/types/components/feedlog-issues-list/feedlog-issues-list.d.ts +2 -2
  40. package/dist/types/components.d.ts +14 -14
  41. package/dist/types/utils/markdown.d.ts +1 -0
  42. package/hydrate/index.js +97 -76
  43. package/hydrate/index.mjs +97 -76
  44. package/package.json +7 -4
  45. package/dist/components/p-RVHxnHRU.js +0 -1
  46. package/dist/components/p-TX_JzdfG.js +0 -3
  47. package/dist/feedlog-toolkit/p-0a9a5af2.entry.js +0 -1
  48. package/dist/feedlog-toolkit/p-B8AIqnOZ.js +0 -2
package/hydrate/index.js CHANGED
@@ -5154,6 +5154,35 @@ ${e}</tr>
5154
5154
  `}strong({tokens:e}){return `<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return `<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return `<code>${O(e,true)}</code>`}br(e){return "<br>"}del({tokens:e}){return `<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let r=this.parser.parseInline(n),i=X(e);if(i===null)return r;e=i;let s='<a href="'+e+'"';return t&&(s+=' title="'+O(t)+'"'),s+=">"+r+"</a>",s}image({href:e,title:t,text:n,tokens:r}){r&&(n=this.parser.parseInline(r,this.parser.textRenderer));let i=X(e);if(i===null)return O(n);e=i;let s=`<img src="${e}" alt="${n}"`;return t&&(s+=` title="${O(t)}"`),s+=">",s}text(e){return "tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:O(e.text)}};var $=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return ""+e}image({text:e}){return ""+e}br(){return ""}checkbox({raw:e}){return e}};var b=class u{options;renderer;textRenderer;constructor(e){this.options=e||T,this.options.renderer=this.options.renderer||new y,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new $;}static parse(e,t){return new u(t).parse(e)}static parseInline(e,t){return new u(t).parseInline(e)}parse(e){let t="";for(let n=0;n<e.length;n++){let r=e[n];if(this.options.extensions?.renderers?.[r.type]){let s=r,a=this.options.extensions.renderers[s.type].call({parser:this},s);if(a!==false||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(s.type)){t+=a||"";continue}}let i=r;switch(i.type){case "space":{t+=this.renderer.space(i);break}case "hr":{t+=this.renderer.hr(i);break}case "heading":{t+=this.renderer.heading(i);break}case "code":{t+=this.renderer.code(i);break}case "table":{t+=this.renderer.table(i);break}case "blockquote":{t+=this.renderer.blockquote(i);break}case "list":{t+=this.renderer.list(i);break}case "checkbox":{t+=this.renderer.checkbox(i);break}case "html":{t+=this.renderer.html(i);break}case "def":{t+=this.renderer.def(i);break}case "paragraph":{t+=this.renderer.paragraph(i);break}case "text":{t+=this.renderer.text(i);break}default:{let s='Token with "'+i.type+'" type was not found.';if(this.options.silent)return console.error(s),"";throw new Error(s)}}}return t}parseInline(e,t=this.renderer){let n="";for(let r=0;r<e.length;r++){let i=e[r];if(this.options.extensions?.renderers?.[i.type]){let a=this.options.extensions.renderers[i.type].call({parser:this},i);if(a!==false||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(i.type)){n+=a||"";continue}}let s=i;switch(s.type){case "escape":{n+=t.text(s);break}case "html":{n+=t.html(s);break}case "link":{n+=t.link(s);break}case "image":{n+=t.image(s);break}case "checkbox":{n+=t.checkbox(s);break}case "strong":{n+=t.strong(s);break}case "em":{n+=t.em(s);break}case "codespan":{n+=t.codespan(s);break}case "br":{n+=t.br(s);break}case "del":{n+=t.del(s);break}case "text":{n+=t.text(s);break}default:{let a='Token with "'+s.type+'" type was not found.';if(this.options.silent)return console.error(a),"";throw new Error(a)}}}return n}};var P=class{options;block;constructor(e){this.options=e||T;}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(){return this.block?x.lex:x.lexInline}provideParser(){return this.block?b.parse:b.parseInline}};var B=class{defaults=M();options=this.setOptions;parse=this.parseMarkdown(true);parseInline=this.parseMarkdown(false);Parser=b;Renderer=y;TextRenderer=$;Lexer=x;Tokenizer=w;Hooks=P;constructor(...e){this.use(...e);}walkTokens(e,t){let n=[];for(let r of e)switch(n=n.concat(t.call(this,r)),r.type){case "table":{let i=r;for(let s of i.header)n=n.concat(this.walkTokens(s.tokens,t));for(let s of i.rows)for(let a of s)n=n.concat(this.walkTokens(a.tokens,t));break}case "list":{let i=r;n=n.concat(this.walkTokens(i.items,t));break}default:{let i=r;this.defaults.extensions?.childTokens?.[i.type]?this.defaults.extensions.childTokens[i.type].forEach(s=>{let a=i[s].flat(1/0);n=n.concat(this.walkTokens(a,t));}):i.tokens&&(n=n.concat(this.walkTokens(i.tokens,t)));}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let r={...n};if(r.async=this.defaults.async||r.async||false,n.extensions&&(n.extensions.forEach(i=>{if(!i.name)throw new Error("extension name required");if("renderer"in i){let s=t.renderers[i.name];s?t.renderers[i.name]=function(...a){let o=i.renderer.apply(this,a);return o===false&&(o=s.apply(this,a)),o}:t.renderers[i.name]=i.renderer;}if("tokenizer"in i){if(!i.level||i.level!=="block"&&i.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let s=t[i.level];s?s.unshift(i.tokenizer):t[i.level]=[i.tokenizer],i.start&&(i.level==="block"?t.startBlock?t.startBlock.push(i.start):t.startBlock=[i.start]:i.level==="inline"&&(t.startInline?t.startInline.push(i.start):t.startInline=[i.start]));}"childTokens"in i&&i.childTokens&&(t.childTokens[i.name]=i.childTokens);}),r.extensions=t),n.renderer){let i=this.defaults.renderer||new y(this.defaults);for(let s in n.renderer){if(!(s in i))throw new Error(`renderer '${s}' does not exist`);if(["options","parser"].includes(s))continue;let a=s,o=n.renderer[a],l=i[a];i[a]=(...p)=>{let c=o.apply(i,p);return c===false&&(c=l.apply(i,p)),c||""};}r.renderer=i;}if(n.tokenizer){let i=this.defaults.tokenizer||new w(this.defaults);for(let s in n.tokenizer){if(!(s in i))throw new Error(`tokenizer '${s}' does not exist`);if(["options","rules","lexer"].includes(s))continue;let a=s,o=n.tokenizer[a],l=i[a];i[a]=(...p)=>{let c=o.apply(i,p);return c===false&&(c=l.apply(i,p)),c};}r.tokenizer=i;}if(n.hooks){let i=this.defaults.hooks||new P;for(let s in n.hooks){if(!(s in i))throw new Error(`hook '${s}' does not exist`);if(["options","block"].includes(s))continue;let a=s,o=n.hooks[a],l=i[a];P.passThroughHooks.has(s)?i[a]=p=>{if(this.defaults.async&&P.passThroughHooksRespectAsync.has(s))return (async()=>{let d=await o.call(i,p);return l.call(i,d)})();let c=o.call(i,p);return l.call(i,c)}:i[a]=(...p)=>{if(this.defaults.async)return (async()=>{let d=await o.apply(i,p);return d===false&&(d=await l.apply(i,p)),d})();let c=o.apply(i,p);return c===false&&(c=l.apply(i,p)),c};}r.hooks=i;}if(n.walkTokens){let i=this.defaults.walkTokens,s=n.walkTokens;r.walkTokens=function(a){let o=[];return o.push(s.call(this,a)),i&&(o=o.concat(i.call(this,a))),o};}this.defaults={...this.defaults,...r};}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return (n,r)=>{let i={...r},s={...this.defaults,...i},a=this.onError(!!s.silent,!!s.async);if(this.defaults.async===true&&i.async===false)return a(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return a(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return a(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(s.hooks&&(s.hooks.options=s,s.hooks.block=e),s.async)return (async()=>{let o=s.hooks?await s.hooks.preprocess(n):n,p=await(s.hooks?await s.hooks.provideLexer():e?x.lex:x.lexInline)(o,s),c=s.hooks?await s.hooks.processAllTokens(p):p;s.walkTokens&&await Promise.all(this.walkTokens(c,s.walkTokens));let h=await(s.hooks?await s.hooks.provideParser():e?b.parse:b.parseInline)(c,s);return s.hooks?await s.hooks.postprocess(h):h})().catch(a);try{s.hooks&&(n=s.hooks.preprocess(n));let l=(s.hooks?s.hooks.provideLexer():e?x.lex:x.lexInline)(n,s);s.hooks&&(l=s.hooks.processAllTokens(l)),s.walkTokens&&this.walkTokens(l,s.walkTokens);let c=(s.hooks?s.hooks.provideParser():e?b.parse:b.parseInline)(l,s);return s.hooks&&(c=s.hooks.postprocess(c)),c}catch(o){return a(o)}}}onError(e,t){return n=>{if(n.message+=`
5155
5155
  Please report this to https://github.com/markedjs/marked.`,e){let r="<p>An error occurred:</p><pre>"+O(n.message+"",true)+"</pre>";return t?Promise.resolve(r):r}if(t)return Promise.reject(n);throw n}}};var L=new B;function g(u,e){return L.parse(u,e)}g.options=g.setOptions=function(u){return L.setOptions(u),g.defaults=L.defaults,H(g.defaults),g};g.getDefaults=M;g.defaults=T;g.use=function(...u){return L.use(...u),g.defaults=L.defaults,H(g.defaults),g};g.walkTokens=function(u,e){return L.walkTokens(u,e)};g.parseInline=L.parseInline;g.Parser=b;g.parser=b.parse;g.Renderer=y;g.TextRenderer=$;g.Lexer=x;g.lexer=x.lex;g.Tokenizer=w;g.Hooks=P;g.parse=g;
5156
5156
 
5157
+ function getDefaultExportFromCjs (x) {
5158
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
5159
+ }
5160
+
5161
+ function getAugmentedNamespace(n) {
5162
+ if (n.__esModule) return n;
5163
+ var f = n.default;
5164
+ if (typeof f == "function") {
5165
+ var a = function a () {
5166
+ if (this instanceof a) {
5167
+ return Reflect.construct(f, arguments, this.constructor);
5168
+ }
5169
+ return f.apply(this, arguments);
5170
+ };
5171
+ a.prototype = f.prototype;
5172
+ } else a = {};
5173
+ Object.defineProperty(a, '__esModule', {value: true});
5174
+ Object.keys(n).forEach(function (k) {
5175
+ var d = Object.getOwnPropertyDescriptor(n, k);
5176
+ Object.defineProperty(a, k, d.get ? d : {
5177
+ enumerable: true,
5178
+ get: function () {
5179
+ return n[k];
5180
+ }
5181
+ });
5182
+ });
5183
+ return a;
5184
+ }
5185
+
5157
5186
  /*! @license DOMPurify 3.3.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.3/LICENSE */
5158
5187
 
5159
5188
  const {
@@ -6545,6 +6574,21 @@ var purify_es = /*#__PURE__*/Object.freeze({
6545
6574
  default: purify
6546
6575
  });
6547
6576
 
6577
+ var require$$0 = /*@__PURE__*/getAugmentedNamespace(purify_es);
6578
+
6579
+ var browser;
6580
+ var hasRequiredBrowser;
6581
+
6582
+ function requireBrowser () {
6583
+ if (hasRequiredBrowser) return browser;
6584
+ hasRequiredBrowser = 1;
6585
+ browser = self.DOMPurify || (self.DOMPurify = require$$0.default || require$$0);
6586
+ return browser;
6587
+ }
6588
+
6589
+ var browserExports = requireBrowser();
6590
+ var DOMPurify = /*@__PURE__*/getDefaultExportFromCjs(browserExports);
6591
+
6548
6592
  /**
6549
6593
  * Parse markdown to sanitized HTML for safe rendering.
6550
6594
  * Uses marked for parsing and DOMPurify for XSS protection.
@@ -6562,7 +6606,7 @@ function parseMarkdown(markdown) {
6562
6606
  throw new Error('marked.parse returned a Promise; async markdown is not supported');
6563
6607
  }
6564
6608
  const html = parsed;
6565
- return purify.sanitize(html, {
6609
+ return DOMPurify.sanitize(html, {
6566
6610
  ALLOWED_TAGS: [
6567
6611
  'p',
6568
6612
  'br',
@@ -6617,10 +6661,11 @@ class FeedlogIssueComponent {
6617
6661
  };
6618
6662
  this.handleUpvote = (event) => {
6619
6663
  event.stopPropagation();
6664
+ const nextUpvoted = !this.issue.hasUpvoted;
6620
6665
  this.feedlogUpvote.emit({
6621
6666
  issueId: this.issue.id,
6622
- currentUpvoted: this.issue.hasUpvoted,
6623
- currentCount: this.issue.upvoteCount,
6667
+ upvoted: nextUpvoted,
6668
+ upvoteCount: Math.max(0, this.issue.upvoteCount + (nextUpvoted ? 1 : -1)),
6624
6669
  });
6625
6670
  };
6626
6671
  }
@@ -6809,7 +6854,7 @@ class FeedlogIssues {
6809
6854
  const containerStyle = {
6810
6855
  maxWidth: this.maxWidth,
6811
6856
  };
6812
- return (hAsync(Host, { key: '15ca787d3e5b45331a6582ea908b35b94b3a528c', class: this.theme === 'dark' ? 'dark' : '' }, hAsync("div", { key: '79d655ca18778660f0156fbdec54764491eaac49', class: "issues-container", style: containerStyle }, (this.heading || this.subtitle) && (hAsync("header", { key: 'e9e1b05451f55db894a1b6248dde4d9d90a96068', class: "issues-header" }, hAsync("div", { key: 'b2921e777986f9c6afc3ba1cbf8023311c868b34', class: "header-content" }, this.heading && hAsync("h1", { key: 'e484da412ff1a92b876f3075489e60be273076b3', class: "issues-title" }, this.heading), this.subtitle && hAsync("p", { key: '5030cbb2fdf2deab3681c1177a14e2b540d2ea33', class: "issues-subtitle" }, this.subtitle)))), this.loading && (hAsync("div", { key: 'f3fb2c02af4637832c518714f670ca2ae2624d49', class: "loading-state", role: "status", "aria-label": "Loading issues" }, hAsync("div", { key: '14e60e4174d22dd2474677a7ec6365d053fe40e7', class: "loading-skeletons" }, [1, 2, 3].map(i => (hAsync("div", { key: i, class: "skeleton-card" }, hAsync("div", { class: "skeleton-content" }, hAsync("div", { class: "skeleton-header" }, hAsync("div", { class: "skeleton-badge" }), hAsync("div", { class: "skeleton-timestamp" })), hAsync("div", { class: "skeleton-main" }, hAsync("div", { class: "skeleton-title" }), hAsync("div", { class: "skeleton-body" }, hAsync("div", { class: "skeleton-line" }), hAsync("div", { class: "skeleton-line short" })), hAsync("div", { class: "skeleton-repo" })), hAsync("div", { class: "skeleton-footer" }, hAsync("div", { class: "skeleton-upvote" }))))))))), this.error && (hAsync("div", { key: '0c301ece57faeee2c6bbf2a4e346a88b6bc535cc', class: "error-state", role: "alert" }, hAsync("div", { key: 'bab84dcbca74730ba44162c57baf65454ffb78c0', class: "error-state-content" }, this.renderErrorIcon(), hAsync("h2", { key: '247b25d17323d08ec9c527ebec1352600614f3be', class: "error-state-title" }, "Something went wrong"), hAsync("p", { key: '45501981e34a2a163e20724881945a0b75ef57d1', class: "error-state-message" }, this.error)))), !this.loading && !this.error && (hAsync("div", { key: 'ca5a2697c898b61121c16a9d1f4320ad35a0bf84' }, this.renderIssuesList(), this.hasMore && (hAsync("div", { key: '1896d074714f083c3e171d0516d1d71155cbcd6a', class: "load-more-container" }, hAsync("feedlog-button", { key: 'b34a2081a91b14e13aa4ace4d67b4d812f4a1d77', onFeedlogClick: this.handleLoadMore, disabled: this.isLoadingMore, variant: "outline" }, this.isLoadingMore ? 'Loading...' : 'Load More Issues'))))))));
6857
+ return (hAsync(Host, { key: 'efed57e0c474b689a24e202f0fb6b67afd310572', class: this.theme === 'dark' ? 'dark' : '' }, hAsync("div", { key: 'ddb7185c3ace088f2883b2dcd193beb8af213cf3', class: "issues-container", style: containerStyle }, (this.heading || this.subtitle) && (hAsync("header", { key: '59aeafb96ac34de3ed7d0ecbd20f958dbc4d9ce9', class: "issues-header" }, hAsync("div", { key: 'cba96e346d2e09c28cf253bca55e5bc822f69762', class: "header-content" }, this.heading && hAsync("h1", { key: '7ce0ea76eb114c453a46592f2e5b1ea81b406cc4', class: "issues-title" }, this.heading), this.subtitle && hAsync("p", { key: 'a83fbcc2baab2aeb2b72ff3dbfc03cd3c77a0278', class: "issues-subtitle" }, this.subtitle)))), this.loading && (hAsync("div", { key: 'cf24d3838ef214697abfc2d8a03182e08e0ed6e7', class: "loading-state", role: "status", "aria-label": "Loading issues" }, hAsync("div", { key: 'd2a1547e4cbd7f41518153d7a8ea757beb384088', class: "loading-skeletons" }, [1, 2, 3].map(i => (hAsync("div", { key: i, class: "skeleton-card" }, hAsync("div", { class: "skeleton-content" }, hAsync("div", { class: "skeleton-header" }, hAsync("div", { class: "skeleton-badge" }), hAsync("div", { class: "skeleton-timestamp" })), hAsync("div", { class: "skeleton-main" }, hAsync("div", { class: "skeleton-title" }), hAsync("div", { class: "skeleton-body" }, hAsync("div", { class: "skeleton-line" }), hAsync("div", { class: "skeleton-line short" })), hAsync("div", { class: "skeleton-repo" })), hAsync("div", { class: "skeleton-footer" }, hAsync("div", { class: "skeleton-upvote" }))))))))), this.error && (hAsync("div", { key: '79c70736a6ba731432ef2ba84c5902e52a2ed864', class: "error-state", role: "alert" }, hAsync("div", { key: '31e987295d26e65c09187ae45e7305a46db27b32', class: "error-state-content" }, this.renderErrorIcon(), hAsync("h2", { key: 'c030fb77e635ee6e50b9bebe16d8a97f75e2921c', class: "error-state-title" }, "Something went wrong"), hAsync("p", { key: '5c725c8d65d304e58c06ce574366f7ab6f18ea59', class: "error-state-message" }, this.error)))), !this.loading && !this.error && (hAsync("div", { key: '4217556c83dbd193eeed23ec50c40ec5fedbf420' }, this.renderIssuesList(), this.hasMore && (hAsync("div", { key: 'df669ef16de0c2316715b97edd9c9af935e96464', class: "load-more-container" }, hAsync("feedlog-button", { key: 'ba1498e81606245a55d0f428e8b3b7b0bf609367', onFeedlogClick: this.handleLoadMore, disabled: this.isLoadingMore, variant: "outline" }, this.isLoadingMore ? 'Loading...' : 'Load More Issues'))))))));
6813
6858
  }
6814
6859
  static get style() { return feedlogIssuesCss(); }
6815
6860
  static get cmpMeta() { return {
@@ -6819,7 +6864,7 @@ class FeedlogIssues {
6819
6864
  "issues": [16],
6820
6865
  "maxWidth": [1, "max-width"],
6821
6866
  "limit": [2],
6822
- "theme": [1025],
6867
+ "theme": [1],
6823
6868
  "heading": [1],
6824
6869
  "subtitle": [1],
6825
6870
  "emptyStateTitle": [1, "empty-state-title"],
@@ -6836,50 +6881,6 @@ class FeedlogIssues {
6836
6881
  }; }
6837
6882
  }
6838
6883
 
6839
- function getDefaultExportFromCjs (x) {
6840
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
6841
- }
6842
-
6843
- function getAugmentedNamespace(n) {
6844
- if (n.__esModule) return n;
6845
- var f = n.default;
6846
- if (typeof f == "function") {
6847
- var a = function a () {
6848
- if (this instanceof a) {
6849
- return Reflect.construct(f, arguments, this.constructor);
6850
- }
6851
- return f.apply(this, arguments);
6852
- };
6853
- a.prototype = f.prototype;
6854
- } else a = {};
6855
- Object.defineProperty(a, '__esModule', {value: true});
6856
- Object.keys(n).forEach(function (k) {
6857
- var d = Object.getOwnPropertyDescriptor(n, k);
6858
- Object.defineProperty(a, k, d.get ? d : {
6859
- enumerable: true,
6860
- get: function () {
6861
- return n[k];
6862
- }
6863
- });
6864
- });
6865
- return a;
6866
- }
6867
-
6868
- var require$$0 = /*@__PURE__*/getAugmentedNamespace(purify_es);
6869
-
6870
- var browser;
6871
- var hasRequiredBrowser;
6872
-
6873
- function requireBrowser () {
6874
- if (hasRequiredBrowser) return browser;
6875
- hasRequiredBrowser = 1;
6876
- browser = self.DOMPurify || (self.DOMPurify = require$$0.default || require$$0);
6877
- return browser;
6878
- }
6879
-
6880
- var browserExports = requireBrowser();
6881
- var DOMPurify = /*@__PURE__*/getDefaultExportFromCjs(browserExports);
6882
-
6883
6884
  /**
6884
6885
  * HTML and XSS sanitization utilities
6885
6886
  */
@@ -6943,7 +6944,7 @@ class FeedlogTimeoutError extends FeedlogError {
6943
6944
  class FeedlogSDK {
6944
6945
  constructor(config) {
6945
6946
  this.config = {
6946
- credentials: 'include',
6947
+ credentials: 'same-origin',
6947
6948
  ...config,
6948
6949
  };
6949
6950
  this.apiKey = this.config.apiKey;
@@ -7246,13 +7247,17 @@ class FeedlogIssuesClient {
7246
7247
  if (!this.sdk || this.isDisconnected) {
7247
7248
  return;
7248
7249
  }
7249
- const { issueId, currentUpvoted, currentCount } = event.detail;
7250
+ const { issueId, upvoted, upvoteCount } = event.detail;
7251
+ const currentIssue = this.issues.find(issue => issue.id === issueId);
7252
+ if (!currentIssue) {
7253
+ return;
7254
+ }
7250
7255
  // Track request to handle race conditions
7251
7256
  const requestId = (this.upvoteRequestIds.get(issueId) || 0) + 1;
7252
7257
  this.upvoteRequestIds.set(issueId, requestId);
7253
7258
  // Optimistic update
7254
7259
  this.issues = this.issues.map(issue => issue.id === issueId
7255
- ? Object.assign(Object.assign({}, issue), { hasUpvoted: !currentUpvoted, upvoteCount: currentUpvoted ? currentCount - 1 : currentCount + 1 }) : issue);
7260
+ ? Object.assign(Object.assign({}, issue), { hasUpvoted: upvoted, upvoteCount }) : issue);
7256
7261
  try {
7257
7262
  const result = await this.sdk.toggleUpvote(issueId);
7258
7263
  // Ignore if component disconnected or request is stale
@@ -7275,16 +7280,13 @@ class FeedlogIssuesClient {
7275
7280
  }
7276
7281
  // Revert optimistic update on error
7277
7282
  this.issues = this.issues.map(issue => issue.id === issueId
7278
- ? Object.assign(Object.assign({}, issue), { hasUpvoted: currentUpvoted, upvoteCount: currentCount }) : issue);
7283
+ ? Object.assign(Object.assign({}, issue), { hasUpvoted: currentIssue.hasUpvoted, upvoteCount: currentIssue.upvoteCount }) : issue);
7279
7284
  const errorMsg = err instanceof Error ? err.message : 'Failed to toggle upvote';
7280
7285
  this.feedlogError.emit({ error: errorMsg });
7281
7286
  }
7282
7287
  };
7283
7288
  }
7284
7289
  componentWillLoad() {
7285
- this.previousType = this.type;
7286
- this.previousLimit = this.limit;
7287
- this.previousSortBy = this.sortBy;
7288
7290
  this.initializeSDK();
7289
7291
  // Return the promise so SSR waits for the fetch before serializing HTML.
7290
7292
  // During client hydration, skip fetch if we already have server-rendered data.
@@ -7298,25 +7300,27 @@ class FeedlogIssuesClient {
7298
7300
  this.isDisconnected = true;
7299
7301
  this.fetchRequestId++;
7300
7302
  }
7301
- componentDidUpdate() {
7302
- // Re-fetch if any props changed
7303
- const typeChanged = this.previousType !== this.type;
7304
- const limitChanged = this.previousLimit !== this.limit;
7305
- const sortByChanged = this.previousSortBy !== this.sortBy;
7306
- if (typeChanged || limitChanged || sortByChanged) {
7307
- // Invalidate any in-flight requests
7308
- this.fetchRequestId++;
7309
- // Reset pagination when filters change
7310
- this.cursor = null;
7311
- this.hasMore = false;
7312
- this.issues = [];
7313
- void this.fetchIssues().catch(() => {
7314
- /* errors handled inside fetchIssues */
7315
- });
7316
- this.previousType = this.type;
7317
- this.previousLimit = this.limit;
7318
- this.previousSortBy = this.sortBy;
7303
+ handleQueryParamChange(newValue, oldValue) {
7304
+ if (newValue === oldValue) {
7305
+ return;
7306
+ }
7307
+ void this.resetAndRefetchIssues();
7308
+ }
7309
+ handleSdkConfigChange(newValue, oldValue) {
7310
+ if (newValue === oldValue) {
7311
+ return;
7319
7312
  }
7313
+ this.initializeSDK();
7314
+ void this.resetAndRefetchIssues();
7315
+ }
7316
+ async resetAndRefetchIssues() {
7317
+ // Invalidate any in-flight requests and reset derived state before reloading.
7318
+ this.fetchRequestId++;
7319
+ this.cursor = null;
7320
+ this.hasMore = false;
7321
+ this.issues = [];
7322
+ this.upvoteRequestIds.clear();
7323
+ await this.fetchIssues();
7320
7324
  }
7321
7325
  initializeSDK() {
7322
7326
  try {
@@ -7431,9 +7435,26 @@ class FeedlogIssuesClient {
7431
7435
  const style = hostBg
7432
7436
  ? { '--feedlog-background': hostBg }
7433
7437
  : undefined;
7434
- return (hAsync("feedlog-issues", { key: '4467ffabd5f18f9af6c8407622fb2554981b54bd', style: style, issues: this.issues, limit: this.limit, maxWidth: this.maxWidth, theme: this.theme, heading: this.heading, subtitle: this.subtitle, emptyStateTitle: this.emptyStateTitle, emptyStateMessage: this.emptyStateMessage, getIssueUrl: this.getIssueUrl, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogLoadMore: async () => this.loadMore() }));
7438
+ return (hAsync("feedlog-issues", { key: 'd98b8366830171a8a09d01cc9e2b19a19850a5fd', style: style, issues: this.issues, limit: this.limit, maxWidth: this.maxWidth, theme: this.theme, heading: this.heading, subtitle: this.subtitle, emptyStateTitle: this.emptyStateTitle, emptyStateMessage: this.emptyStateMessage, getIssueUrl: this.getIssueUrl, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogLoadMore: async () => this.loadMore() }));
7435
7439
  }
7436
7440
  get el() { return getElement(this); }
7441
+ static get watchers() { return {
7442
+ "type": [{
7443
+ "handleQueryParamChange": 0
7444
+ }],
7445
+ "limit": [{
7446
+ "handleQueryParamChange": 0
7447
+ }],
7448
+ "sortBy": [{
7449
+ "handleQueryParamChange": 0
7450
+ }],
7451
+ "apiKey": [{
7452
+ "handleSdkConfigChange": 0
7453
+ }],
7454
+ "endpoint": [{
7455
+ "handleSdkConfigChange": 0
7456
+ }]
7457
+ }; }
7437
7458
  static get cmpMeta() { return {
7438
7459
  "$flags$": 9,
7439
7460
  "$tagName$": "feedlog-issues-client",
@@ -7536,7 +7557,7 @@ class FeedlogIssuesList {
7536
7557
  }
7537
7558
  render() {
7538
7559
  const visibleIssues = this.getVisibleIssues();
7539
- return (hAsync(Host, { key: '7721ed64730cd8e6b508fc829767ea79b2531628', class: this.theme === 'dark' ? 'dark' : '' }, hAsync("div", { key: '6a2d83f46ce2391294cef018ec243dd13d06a063', class: "issues-list" }, visibleIssues.length === 0 ? (hAsync("div", { class: "empty-state" }, this.emptyStateTitle && this.emptyStateMessage ? (hAsync("div", { class: "empty-state-content" }, this.renderEmptyStateIllustration(), hAsync("h2", { class: "empty-state-title" }, this.emptyStateTitle), hAsync("p", { class: "empty-state-message" }, this.emptyStateMessage))) : (hAsync("p", null, "No issues found")))) : (visibleIssues.map(issue => {
7560
+ return (hAsync(Host, { key: 'b2b009625ec2cec47449afd7602202a9f95b8740', class: this.theme === 'dark' ? 'dark' : '' }, hAsync("div", { key: 'f108815569c064e45a78272a83f7048708470a3d', class: "issues-list" }, visibleIssues.length === 0 ? (hAsync("div", { class: "empty-state" }, this.emptyStateTitle && this.emptyStateMessage ? (hAsync("div", { class: "empty-state-content" }, this.renderEmptyStateIllustration(), hAsync("h2", { class: "empty-state-title" }, this.emptyStateTitle), hAsync("p", { class: "empty-state-message" }, this.emptyStateMessage))) : (hAsync("p", null, "No issues found")))) : (visibleIssues.map(issue => {
7540
7561
  var _a, _b;
7541
7562
  return (hAsync("feedlog-issue", { key: issue.id, issue: issue, issueUrl: (_b = (_a = this.getIssueUrl) === null || _a === void 0 ? void 0 : _a.call(this, issue)) !== null && _b !== void 0 ? _b : undefined, theme: this.theme, onFeedlogUpvote: (e) => this.handleUpvote(e) }));
7542
7563
  }))), this.renderPagination()));
package/hydrate/index.mjs CHANGED
@@ -5152,6 +5152,35 @@ ${e}</tr>
5152
5152
  `}strong({tokens:e}){return `<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return `<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return `<code>${O(e,true)}</code>`}br(e){return "<br>"}del({tokens:e}){return `<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let r=this.parser.parseInline(n),i=X(e);if(i===null)return r;e=i;let s='<a href="'+e+'"';return t&&(s+=' title="'+O(t)+'"'),s+=">"+r+"</a>",s}image({href:e,title:t,text:n,tokens:r}){r&&(n=this.parser.parseInline(r,this.parser.textRenderer));let i=X(e);if(i===null)return O(n);e=i;let s=`<img src="${e}" alt="${n}"`;return t&&(s+=` title="${O(t)}"`),s+=">",s}text(e){return "tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:O(e.text)}};var $=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return ""+e}image({text:e}){return ""+e}br(){return ""}checkbox({raw:e}){return e}};var b=class u{options;renderer;textRenderer;constructor(e){this.options=e||T,this.options.renderer=this.options.renderer||new y,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new $;}static parse(e,t){return new u(t).parse(e)}static parseInline(e,t){return new u(t).parseInline(e)}parse(e){let t="";for(let n=0;n<e.length;n++){let r=e[n];if(this.options.extensions?.renderers?.[r.type]){let s=r,a=this.options.extensions.renderers[s.type].call({parser:this},s);if(a!==false||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(s.type)){t+=a||"";continue}}let i=r;switch(i.type){case "space":{t+=this.renderer.space(i);break}case "hr":{t+=this.renderer.hr(i);break}case "heading":{t+=this.renderer.heading(i);break}case "code":{t+=this.renderer.code(i);break}case "table":{t+=this.renderer.table(i);break}case "blockquote":{t+=this.renderer.blockquote(i);break}case "list":{t+=this.renderer.list(i);break}case "checkbox":{t+=this.renderer.checkbox(i);break}case "html":{t+=this.renderer.html(i);break}case "def":{t+=this.renderer.def(i);break}case "paragraph":{t+=this.renderer.paragraph(i);break}case "text":{t+=this.renderer.text(i);break}default:{let s='Token with "'+i.type+'" type was not found.';if(this.options.silent)return console.error(s),"";throw new Error(s)}}}return t}parseInline(e,t=this.renderer){let n="";for(let r=0;r<e.length;r++){let i=e[r];if(this.options.extensions?.renderers?.[i.type]){let a=this.options.extensions.renderers[i.type].call({parser:this},i);if(a!==false||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(i.type)){n+=a||"";continue}}let s=i;switch(s.type){case "escape":{n+=t.text(s);break}case "html":{n+=t.html(s);break}case "link":{n+=t.link(s);break}case "image":{n+=t.image(s);break}case "checkbox":{n+=t.checkbox(s);break}case "strong":{n+=t.strong(s);break}case "em":{n+=t.em(s);break}case "codespan":{n+=t.codespan(s);break}case "br":{n+=t.br(s);break}case "del":{n+=t.del(s);break}case "text":{n+=t.text(s);break}default:{let a='Token with "'+s.type+'" type was not found.';if(this.options.silent)return console.error(a),"";throw new Error(a)}}}return n}};var P=class{options;block;constructor(e){this.options=e||T;}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(){return this.block?x.lex:x.lexInline}provideParser(){return this.block?b.parse:b.parseInline}};var B=class{defaults=M();options=this.setOptions;parse=this.parseMarkdown(true);parseInline=this.parseMarkdown(false);Parser=b;Renderer=y;TextRenderer=$;Lexer=x;Tokenizer=w;Hooks=P;constructor(...e){this.use(...e);}walkTokens(e,t){let n=[];for(let r of e)switch(n=n.concat(t.call(this,r)),r.type){case "table":{let i=r;for(let s of i.header)n=n.concat(this.walkTokens(s.tokens,t));for(let s of i.rows)for(let a of s)n=n.concat(this.walkTokens(a.tokens,t));break}case "list":{let i=r;n=n.concat(this.walkTokens(i.items,t));break}default:{let i=r;this.defaults.extensions?.childTokens?.[i.type]?this.defaults.extensions.childTokens[i.type].forEach(s=>{let a=i[s].flat(1/0);n=n.concat(this.walkTokens(a,t));}):i.tokens&&(n=n.concat(this.walkTokens(i.tokens,t)));}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let r={...n};if(r.async=this.defaults.async||r.async||false,n.extensions&&(n.extensions.forEach(i=>{if(!i.name)throw new Error("extension name required");if("renderer"in i){let s=t.renderers[i.name];s?t.renderers[i.name]=function(...a){let o=i.renderer.apply(this,a);return o===false&&(o=s.apply(this,a)),o}:t.renderers[i.name]=i.renderer;}if("tokenizer"in i){if(!i.level||i.level!=="block"&&i.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let s=t[i.level];s?s.unshift(i.tokenizer):t[i.level]=[i.tokenizer],i.start&&(i.level==="block"?t.startBlock?t.startBlock.push(i.start):t.startBlock=[i.start]:i.level==="inline"&&(t.startInline?t.startInline.push(i.start):t.startInline=[i.start]));}"childTokens"in i&&i.childTokens&&(t.childTokens[i.name]=i.childTokens);}),r.extensions=t),n.renderer){let i=this.defaults.renderer||new y(this.defaults);for(let s in n.renderer){if(!(s in i))throw new Error(`renderer '${s}' does not exist`);if(["options","parser"].includes(s))continue;let a=s,o=n.renderer[a],l=i[a];i[a]=(...p)=>{let c=o.apply(i,p);return c===false&&(c=l.apply(i,p)),c||""};}r.renderer=i;}if(n.tokenizer){let i=this.defaults.tokenizer||new w(this.defaults);for(let s in n.tokenizer){if(!(s in i))throw new Error(`tokenizer '${s}' does not exist`);if(["options","rules","lexer"].includes(s))continue;let a=s,o=n.tokenizer[a],l=i[a];i[a]=(...p)=>{let c=o.apply(i,p);return c===false&&(c=l.apply(i,p)),c};}r.tokenizer=i;}if(n.hooks){let i=this.defaults.hooks||new P;for(let s in n.hooks){if(!(s in i))throw new Error(`hook '${s}' does not exist`);if(["options","block"].includes(s))continue;let a=s,o=n.hooks[a],l=i[a];P.passThroughHooks.has(s)?i[a]=p=>{if(this.defaults.async&&P.passThroughHooksRespectAsync.has(s))return (async()=>{let d=await o.call(i,p);return l.call(i,d)})();let c=o.call(i,p);return l.call(i,c)}:i[a]=(...p)=>{if(this.defaults.async)return (async()=>{let d=await o.apply(i,p);return d===false&&(d=await l.apply(i,p)),d})();let c=o.apply(i,p);return c===false&&(c=l.apply(i,p)),c};}r.hooks=i;}if(n.walkTokens){let i=this.defaults.walkTokens,s=n.walkTokens;r.walkTokens=function(a){let o=[];return o.push(s.call(this,a)),i&&(o=o.concat(i.call(this,a))),o};}this.defaults={...this.defaults,...r};}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return (n,r)=>{let i={...r},s={...this.defaults,...i},a=this.onError(!!s.silent,!!s.async);if(this.defaults.async===true&&i.async===false)return a(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return a(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return a(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(s.hooks&&(s.hooks.options=s,s.hooks.block=e),s.async)return (async()=>{let o=s.hooks?await s.hooks.preprocess(n):n,p=await(s.hooks?await s.hooks.provideLexer():e?x.lex:x.lexInline)(o,s),c=s.hooks?await s.hooks.processAllTokens(p):p;s.walkTokens&&await Promise.all(this.walkTokens(c,s.walkTokens));let h=await(s.hooks?await s.hooks.provideParser():e?b.parse:b.parseInline)(c,s);return s.hooks?await s.hooks.postprocess(h):h})().catch(a);try{s.hooks&&(n=s.hooks.preprocess(n));let l=(s.hooks?s.hooks.provideLexer():e?x.lex:x.lexInline)(n,s);s.hooks&&(l=s.hooks.processAllTokens(l)),s.walkTokens&&this.walkTokens(l,s.walkTokens);let c=(s.hooks?s.hooks.provideParser():e?b.parse:b.parseInline)(l,s);return s.hooks&&(c=s.hooks.postprocess(c)),c}catch(o){return a(o)}}}onError(e,t){return n=>{if(n.message+=`
5153
5153
  Please report this to https://github.com/markedjs/marked.`,e){let r="<p>An error occurred:</p><pre>"+O(n.message+"",true)+"</pre>";return t?Promise.resolve(r):r}if(t)return Promise.reject(n);throw n}}};var L=new B;function g(u,e){return L.parse(u,e)}g.options=g.setOptions=function(u){return L.setOptions(u),g.defaults=L.defaults,H(g.defaults),g};g.getDefaults=M;g.defaults=T;g.use=function(...u){return L.use(...u),g.defaults=L.defaults,H(g.defaults),g};g.walkTokens=function(u,e){return L.walkTokens(u,e)};g.parseInline=L.parseInline;g.Parser=b;g.parser=b.parse;g.Renderer=y;g.TextRenderer=$;g.Lexer=x;g.lexer=x.lex;g.Tokenizer=w;g.Hooks=P;g.parse=g;
5154
5154
 
5155
+ function getDefaultExportFromCjs (x) {
5156
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
5157
+ }
5158
+
5159
+ function getAugmentedNamespace(n) {
5160
+ if (n.__esModule) return n;
5161
+ var f = n.default;
5162
+ if (typeof f == "function") {
5163
+ var a = function a () {
5164
+ if (this instanceof a) {
5165
+ return Reflect.construct(f, arguments, this.constructor);
5166
+ }
5167
+ return f.apply(this, arguments);
5168
+ };
5169
+ a.prototype = f.prototype;
5170
+ } else a = {};
5171
+ Object.defineProperty(a, '__esModule', {value: true});
5172
+ Object.keys(n).forEach(function (k) {
5173
+ var d = Object.getOwnPropertyDescriptor(n, k);
5174
+ Object.defineProperty(a, k, d.get ? d : {
5175
+ enumerable: true,
5176
+ get: function () {
5177
+ return n[k];
5178
+ }
5179
+ });
5180
+ });
5181
+ return a;
5182
+ }
5183
+
5155
5184
  /*! @license DOMPurify 3.3.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.3/LICENSE */
5156
5185
 
5157
5186
  const {
@@ -6543,6 +6572,21 @@ var purify_es = /*#__PURE__*/Object.freeze({
6543
6572
  default: purify
6544
6573
  });
6545
6574
 
6575
+ var require$$0 = /*@__PURE__*/getAugmentedNamespace(purify_es);
6576
+
6577
+ var browser;
6578
+ var hasRequiredBrowser;
6579
+
6580
+ function requireBrowser () {
6581
+ if (hasRequiredBrowser) return browser;
6582
+ hasRequiredBrowser = 1;
6583
+ browser = self.DOMPurify || (self.DOMPurify = require$$0.default || require$$0);
6584
+ return browser;
6585
+ }
6586
+
6587
+ var browserExports = requireBrowser();
6588
+ var DOMPurify = /*@__PURE__*/getDefaultExportFromCjs(browserExports);
6589
+
6546
6590
  /**
6547
6591
  * Parse markdown to sanitized HTML for safe rendering.
6548
6592
  * Uses marked for parsing and DOMPurify for XSS protection.
@@ -6560,7 +6604,7 @@ function parseMarkdown(markdown) {
6560
6604
  throw new Error('marked.parse returned a Promise; async markdown is not supported');
6561
6605
  }
6562
6606
  const html = parsed;
6563
- return purify.sanitize(html, {
6607
+ return DOMPurify.sanitize(html, {
6564
6608
  ALLOWED_TAGS: [
6565
6609
  'p',
6566
6610
  'br',
@@ -6615,10 +6659,11 @@ class FeedlogIssueComponent {
6615
6659
  };
6616
6660
  this.handleUpvote = (event) => {
6617
6661
  event.stopPropagation();
6662
+ const nextUpvoted = !this.issue.hasUpvoted;
6618
6663
  this.feedlogUpvote.emit({
6619
6664
  issueId: this.issue.id,
6620
- currentUpvoted: this.issue.hasUpvoted,
6621
- currentCount: this.issue.upvoteCount,
6665
+ upvoted: nextUpvoted,
6666
+ upvoteCount: Math.max(0, this.issue.upvoteCount + (nextUpvoted ? 1 : -1)),
6622
6667
  });
6623
6668
  };
6624
6669
  }
@@ -6807,7 +6852,7 @@ class FeedlogIssues {
6807
6852
  const containerStyle = {
6808
6853
  maxWidth: this.maxWidth,
6809
6854
  };
6810
- return (hAsync(Host, { key: '15ca787d3e5b45331a6582ea908b35b94b3a528c', class: this.theme === 'dark' ? 'dark' : '' }, hAsync("div", { key: '79d655ca18778660f0156fbdec54764491eaac49', class: "issues-container", style: containerStyle }, (this.heading || this.subtitle) && (hAsync("header", { key: 'e9e1b05451f55db894a1b6248dde4d9d90a96068', class: "issues-header" }, hAsync("div", { key: 'b2921e777986f9c6afc3ba1cbf8023311c868b34', class: "header-content" }, this.heading && hAsync("h1", { key: 'e484da412ff1a92b876f3075489e60be273076b3', class: "issues-title" }, this.heading), this.subtitle && hAsync("p", { key: '5030cbb2fdf2deab3681c1177a14e2b540d2ea33', class: "issues-subtitle" }, this.subtitle)))), this.loading && (hAsync("div", { key: 'f3fb2c02af4637832c518714f670ca2ae2624d49', class: "loading-state", role: "status", "aria-label": "Loading issues" }, hAsync("div", { key: '14e60e4174d22dd2474677a7ec6365d053fe40e7', class: "loading-skeletons" }, [1, 2, 3].map(i => (hAsync("div", { key: i, class: "skeleton-card" }, hAsync("div", { class: "skeleton-content" }, hAsync("div", { class: "skeleton-header" }, hAsync("div", { class: "skeleton-badge" }), hAsync("div", { class: "skeleton-timestamp" })), hAsync("div", { class: "skeleton-main" }, hAsync("div", { class: "skeleton-title" }), hAsync("div", { class: "skeleton-body" }, hAsync("div", { class: "skeleton-line" }), hAsync("div", { class: "skeleton-line short" })), hAsync("div", { class: "skeleton-repo" })), hAsync("div", { class: "skeleton-footer" }, hAsync("div", { class: "skeleton-upvote" }))))))))), this.error && (hAsync("div", { key: '0c301ece57faeee2c6bbf2a4e346a88b6bc535cc', class: "error-state", role: "alert" }, hAsync("div", { key: 'bab84dcbca74730ba44162c57baf65454ffb78c0', class: "error-state-content" }, this.renderErrorIcon(), hAsync("h2", { key: '247b25d17323d08ec9c527ebec1352600614f3be', class: "error-state-title" }, "Something went wrong"), hAsync("p", { key: '45501981e34a2a163e20724881945a0b75ef57d1', class: "error-state-message" }, this.error)))), !this.loading && !this.error && (hAsync("div", { key: 'ca5a2697c898b61121c16a9d1f4320ad35a0bf84' }, this.renderIssuesList(), this.hasMore && (hAsync("div", { key: '1896d074714f083c3e171d0516d1d71155cbcd6a', class: "load-more-container" }, hAsync("feedlog-button", { key: 'b34a2081a91b14e13aa4ace4d67b4d812f4a1d77', onFeedlogClick: this.handleLoadMore, disabled: this.isLoadingMore, variant: "outline" }, this.isLoadingMore ? 'Loading...' : 'Load More Issues'))))))));
6855
+ return (hAsync(Host, { key: 'efed57e0c474b689a24e202f0fb6b67afd310572', class: this.theme === 'dark' ? 'dark' : '' }, hAsync("div", { key: 'ddb7185c3ace088f2883b2dcd193beb8af213cf3', class: "issues-container", style: containerStyle }, (this.heading || this.subtitle) && (hAsync("header", { key: '59aeafb96ac34de3ed7d0ecbd20f958dbc4d9ce9', class: "issues-header" }, hAsync("div", { key: 'cba96e346d2e09c28cf253bca55e5bc822f69762', class: "header-content" }, this.heading && hAsync("h1", { key: '7ce0ea76eb114c453a46592f2e5b1ea81b406cc4', class: "issues-title" }, this.heading), this.subtitle && hAsync("p", { key: 'a83fbcc2baab2aeb2b72ff3dbfc03cd3c77a0278', class: "issues-subtitle" }, this.subtitle)))), this.loading && (hAsync("div", { key: 'cf24d3838ef214697abfc2d8a03182e08e0ed6e7', class: "loading-state", role: "status", "aria-label": "Loading issues" }, hAsync("div", { key: 'd2a1547e4cbd7f41518153d7a8ea757beb384088', class: "loading-skeletons" }, [1, 2, 3].map(i => (hAsync("div", { key: i, class: "skeleton-card" }, hAsync("div", { class: "skeleton-content" }, hAsync("div", { class: "skeleton-header" }, hAsync("div", { class: "skeleton-badge" }), hAsync("div", { class: "skeleton-timestamp" })), hAsync("div", { class: "skeleton-main" }, hAsync("div", { class: "skeleton-title" }), hAsync("div", { class: "skeleton-body" }, hAsync("div", { class: "skeleton-line" }), hAsync("div", { class: "skeleton-line short" })), hAsync("div", { class: "skeleton-repo" })), hAsync("div", { class: "skeleton-footer" }, hAsync("div", { class: "skeleton-upvote" }))))))))), this.error && (hAsync("div", { key: '79c70736a6ba731432ef2ba84c5902e52a2ed864', class: "error-state", role: "alert" }, hAsync("div", { key: '31e987295d26e65c09187ae45e7305a46db27b32', class: "error-state-content" }, this.renderErrorIcon(), hAsync("h2", { key: 'c030fb77e635ee6e50b9bebe16d8a97f75e2921c', class: "error-state-title" }, "Something went wrong"), hAsync("p", { key: '5c725c8d65d304e58c06ce574366f7ab6f18ea59', class: "error-state-message" }, this.error)))), !this.loading && !this.error && (hAsync("div", { key: '4217556c83dbd193eeed23ec50c40ec5fedbf420' }, this.renderIssuesList(), this.hasMore && (hAsync("div", { key: 'df669ef16de0c2316715b97edd9c9af935e96464', class: "load-more-container" }, hAsync("feedlog-button", { key: 'ba1498e81606245a55d0f428e8b3b7b0bf609367', onFeedlogClick: this.handleLoadMore, disabled: this.isLoadingMore, variant: "outline" }, this.isLoadingMore ? 'Loading...' : 'Load More Issues'))))))));
6811
6856
  }
6812
6857
  static get style() { return feedlogIssuesCss(); }
6813
6858
  static get cmpMeta() { return {
@@ -6817,7 +6862,7 @@ class FeedlogIssues {
6817
6862
  "issues": [16],
6818
6863
  "maxWidth": [1, "max-width"],
6819
6864
  "limit": [2],
6820
- "theme": [1025],
6865
+ "theme": [1],
6821
6866
  "heading": [1],
6822
6867
  "subtitle": [1],
6823
6868
  "emptyStateTitle": [1, "empty-state-title"],
@@ -6834,50 +6879,6 @@ class FeedlogIssues {
6834
6879
  }; }
6835
6880
  }
6836
6881
 
6837
- function getDefaultExportFromCjs (x) {
6838
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
6839
- }
6840
-
6841
- function getAugmentedNamespace(n) {
6842
- if (n.__esModule) return n;
6843
- var f = n.default;
6844
- if (typeof f == "function") {
6845
- var a = function a () {
6846
- if (this instanceof a) {
6847
- return Reflect.construct(f, arguments, this.constructor);
6848
- }
6849
- return f.apply(this, arguments);
6850
- };
6851
- a.prototype = f.prototype;
6852
- } else a = {};
6853
- Object.defineProperty(a, '__esModule', {value: true});
6854
- Object.keys(n).forEach(function (k) {
6855
- var d = Object.getOwnPropertyDescriptor(n, k);
6856
- Object.defineProperty(a, k, d.get ? d : {
6857
- enumerable: true,
6858
- get: function () {
6859
- return n[k];
6860
- }
6861
- });
6862
- });
6863
- return a;
6864
- }
6865
-
6866
- var require$$0 = /*@__PURE__*/getAugmentedNamespace(purify_es);
6867
-
6868
- var browser;
6869
- var hasRequiredBrowser;
6870
-
6871
- function requireBrowser () {
6872
- if (hasRequiredBrowser) return browser;
6873
- hasRequiredBrowser = 1;
6874
- browser = self.DOMPurify || (self.DOMPurify = require$$0.default || require$$0);
6875
- return browser;
6876
- }
6877
-
6878
- var browserExports = requireBrowser();
6879
- var DOMPurify = /*@__PURE__*/getDefaultExportFromCjs(browserExports);
6880
-
6881
6882
  /**
6882
6883
  * HTML and XSS sanitization utilities
6883
6884
  */
@@ -6941,7 +6942,7 @@ class FeedlogTimeoutError extends FeedlogError {
6941
6942
  class FeedlogSDK {
6942
6943
  constructor(config) {
6943
6944
  this.config = {
6944
- credentials: 'include',
6945
+ credentials: 'same-origin',
6945
6946
  ...config,
6946
6947
  };
6947
6948
  this.apiKey = this.config.apiKey;
@@ -7244,13 +7245,17 @@ class FeedlogIssuesClient {
7244
7245
  if (!this.sdk || this.isDisconnected) {
7245
7246
  return;
7246
7247
  }
7247
- const { issueId, currentUpvoted, currentCount } = event.detail;
7248
+ const { issueId, upvoted, upvoteCount } = event.detail;
7249
+ const currentIssue = this.issues.find(issue => issue.id === issueId);
7250
+ if (!currentIssue) {
7251
+ return;
7252
+ }
7248
7253
  // Track request to handle race conditions
7249
7254
  const requestId = (this.upvoteRequestIds.get(issueId) || 0) + 1;
7250
7255
  this.upvoteRequestIds.set(issueId, requestId);
7251
7256
  // Optimistic update
7252
7257
  this.issues = this.issues.map(issue => issue.id === issueId
7253
- ? Object.assign(Object.assign({}, issue), { hasUpvoted: !currentUpvoted, upvoteCount: currentUpvoted ? currentCount - 1 : currentCount + 1 }) : issue);
7258
+ ? Object.assign(Object.assign({}, issue), { hasUpvoted: upvoted, upvoteCount }) : issue);
7254
7259
  try {
7255
7260
  const result = await this.sdk.toggleUpvote(issueId);
7256
7261
  // Ignore if component disconnected or request is stale
@@ -7273,16 +7278,13 @@ class FeedlogIssuesClient {
7273
7278
  }
7274
7279
  // Revert optimistic update on error
7275
7280
  this.issues = this.issues.map(issue => issue.id === issueId
7276
- ? Object.assign(Object.assign({}, issue), { hasUpvoted: currentUpvoted, upvoteCount: currentCount }) : issue);
7281
+ ? Object.assign(Object.assign({}, issue), { hasUpvoted: currentIssue.hasUpvoted, upvoteCount: currentIssue.upvoteCount }) : issue);
7277
7282
  const errorMsg = err instanceof Error ? err.message : 'Failed to toggle upvote';
7278
7283
  this.feedlogError.emit({ error: errorMsg });
7279
7284
  }
7280
7285
  };
7281
7286
  }
7282
7287
  componentWillLoad() {
7283
- this.previousType = this.type;
7284
- this.previousLimit = this.limit;
7285
- this.previousSortBy = this.sortBy;
7286
7288
  this.initializeSDK();
7287
7289
  // Return the promise so SSR waits for the fetch before serializing HTML.
7288
7290
  // During client hydration, skip fetch if we already have server-rendered data.
@@ -7296,25 +7298,27 @@ class FeedlogIssuesClient {
7296
7298
  this.isDisconnected = true;
7297
7299
  this.fetchRequestId++;
7298
7300
  }
7299
- componentDidUpdate() {
7300
- // Re-fetch if any props changed
7301
- const typeChanged = this.previousType !== this.type;
7302
- const limitChanged = this.previousLimit !== this.limit;
7303
- const sortByChanged = this.previousSortBy !== this.sortBy;
7304
- if (typeChanged || limitChanged || sortByChanged) {
7305
- // Invalidate any in-flight requests
7306
- this.fetchRequestId++;
7307
- // Reset pagination when filters change
7308
- this.cursor = null;
7309
- this.hasMore = false;
7310
- this.issues = [];
7311
- void this.fetchIssues().catch(() => {
7312
- /* errors handled inside fetchIssues */
7313
- });
7314
- this.previousType = this.type;
7315
- this.previousLimit = this.limit;
7316
- this.previousSortBy = this.sortBy;
7301
+ handleQueryParamChange(newValue, oldValue) {
7302
+ if (newValue === oldValue) {
7303
+ return;
7304
+ }
7305
+ void this.resetAndRefetchIssues();
7306
+ }
7307
+ handleSdkConfigChange(newValue, oldValue) {
7308
+ if (newValue === oldValue) {
7309
+ return;
7317
7310
  }
7311
+ this.initializeSDK();
7312
+ void this.resetAndRefetchIssues();
7313
+ }
7314
+ async resetAndRefetchIssues() {
7315
+ // Invalidate any in-flight requests and reset derived state before reloading.
7316
+ this.fetchRequestId++;
7317
+ this.cursor = null;
7318
+ this.hasMore = false;
7319
+ this.issues = [];
7320
+ this.upvoteRequestIds.clear();
7321
+ await this.fetchIssues();
7318
7322
  }
7319
7323
  initializeSDK() {
7320
7324
  try {
@@ -7429,9 +7433,26 @@ class FeedlogIssuesClient {
7429
7433
  const style = hostBg
7430
7434
  ? { '--feedlog-background': hostBg }
7431
7435
  : undefined;
7432
- return (hAsync("feedlog-issues", { key: '4467ffabd5f18f9af6c8407622fb2554981b54bd', style: style, issues: this.issues, limit: this.limit, maxWidth: this.maxWidth, theme: this.theme, heading: this.heading, subtitle: this.subtitle, emptyStateTitle: this.emptyStateTitle, emptyStateMessage: this.emptyStateMessage, getIssueUrl: this.getIssueUrl, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogLoadMore: async () => this.loadMore() }));
7436
+ return (hAsync("feedlog-issues", { key: 'd98b8366830171a8a09d01cc9e2b19a19850a5fd', style: style, issues: this.issues, limit: this.limit, maxWidth: this.maxWidth, theme: this.theme, heading: this.heading, subtitle: this.subtitle, emptyStateTitle: this.emptyStateTitle, emptyStateMessage: this.emptyStateMessage, getIssueUrl: this.getIssueUrl, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogLoadMore: async () => this.loadMore() }));
7433
7437
  }
7434
7438
  get el() { return getElement(this); }
7439
+ static get watchers() { return {
7440
+ "type": [{
7441
+ "handleQueryParamChange": 0
7442
+ }],
7443
+ "limit": [{
7444
+ "handleQueryParamChange": 0
7445
+ }],
7446
+ "sortBy": [{
7447
+ "handleQueryParamChange": 0
7448
+ }],
7449
+ "apiKey": [{
7450
+ "handleSdkConfigChange": 0
7451
+ }],
7452
+ "endpoint": [{
7453
+ "handleSdkConfigChange": 0
7454
+ }]
7455
+ }; }
7435
7456
  static get cmpMeta() { return {
7436
7457
  "$flags$": 9,
7437
7458
  "$tagName$": "feedlog-issues-client",
@@ -7534,7 +7555,7 @@ class FeedlogIssuesList {
7534
7555
  }
7535
7556
  render() {
7536
7557
  const visibleIssues = this.getVisibleIssues();
7537
- return (hAsync(Host, { key: '7721ed64730cd8e6b508fc829767ea79b2531628', class: this.theme === 'dark' ? 'dark' : '' }, hAsync("div", { key: '6a2d83f46ce2391294cef018ec243dd13d06a063', class: "issues-list" }, visibleIssues.length === 0 ? (hAsync("div", { class: "empty-state" }, this.emptyStateTitle && this.emptyStateMessage ? (hAsync("div", { class: "empty-state-content" }, this.renderEmptyStateIllustration(), hAsync("h2", { class: "empty-state-title" }, this.emptyStateTitle), hAsync("p", { class: "empty-state-message" }, this.emptyStateMessage))) : (hAsync("p", null, "No issues found")))) : (visibleIssues.map(issue => {
7558
+ return (hAsync(Host, { key: 'b2b009625ec2cec47449afd7602202a9f95b8740', class: this.theme === 'dark' ? 'dark' : '' }, hAsync("div", { key: 'f108815569c064e45a78272a83f7048708470a3d', class: "issues-list" }, visibleIssues.length === 0 ? (hAsync("div", { class: "empty-state" }, this.emptyStateTitle && this.emptyStateMessage ? (hAsync("div", { class: "empty-state-content" }, this.renderEmptyStateIllustration(), hAsync("h2", { class: "empty-state-title" }, this.emptyStateTitle), hAsync("p", { class: "empty-state-message" }, this.emptyStateMessage))) : (hAsync("p", null, "No issues found")))) : (visibleIssues.map(issue => {
7538
7559
  var _a, _b;
7539
7560
  return (hAsync("feedlog-issue", { key: issue.id, issue: issue, issueUrl: (_b = (_a = this.getIssueUrl) === null || _a === void 0 ? void 0 : _a.call(this, issue)) !== null && _b !== void 0 ? _b : undefined, theme: this.theme, onFeedlogUpvote: (e) => this.handleUpvote(e) }));
7540
7561
  }))), this.renderPagination()));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feedlog-ai/webcomponents",
3
- "version": "0.0.42",
3
+ "version": "0.0.44",
4
4
  "description": "Stencil web components for Feedlog Toolkit - Data visualization components",
5
5
  "main": "./dist/index.cjs.js",
6
6
  "module": "./dist/index.js",
@@ -52,6 +52,9 @@
52
52
  "loader",
53
53
  "hydrate"
54
54
  ],
55
+ "sideEffects": [
56
+ "dist/components/*.js"
57
+ ],
55
58
  "scripts": {
56
59
  "build": "stencil build",
57
60
  "prepack": "npm run build",
@@ -66,9 +69,9 @@
66
69
  "clean": "rm -rf dist loader"
67
70
  },
68
71
  "dependencies": {
69
- "@feedlog-ai/core": "^0.0.42",
70
- "dompurify": "^3.3.1",
71
- "marked": "^17.0.2"
72
+ "@feedlog-ai/core": "^0.0.44",
73
+ "isomorphic-dompurify": "^2.16.0",
74
+ "marked": "~17.0.2"
72
75
  },
73
76
  "devDependencies": {
74
77
  "@stencil/core": "^4.0.0",