feat: add native Web Component wrapper for SocialShareButton#108
feat: add native Web Component wrapper for SocialShareButton#108Muneerali199 wants to merge 3 commits intoAOSSIE-Org:mainfrom
Conversation
- Created social-share-button-webcomponent.js with a native Custom Element - No external dependencies (pure vanilla Web Component) - Can be used as <social-share-button> HTML tag in any framework - Supports all SocialShareButton options as attributes/properties - Uses Shadow DOM for style encapsulation Fixes AOSSIE-Org#50
🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
.github/copilot/integrate-analytics.prompt.md (1)
287-296:⚠️ Potential issue | 🟡 MinorRemove stray diff markers from the consent snippet.
Line 287 and surrounding lines include literal
+prefixes, so copied code is invalid JS.Suggested fix
-+const shareButtonInstance = new SocialShareButton({ -+ container: "#share-button", -+ analytics: false, -+}); -+ -+// Activate only after CMP consent +const shareButtonInstance = new SocialShareButton({ + container: '#share-button', + analytics: false, +}); + +// Activate only after CMP consent consentManager.onConsent("analytics", () => { shareButtonInstance.updateOptions({ -+ analytics: true, + analytics: true, analyticsPlugins: [new GoogleAnalyticsAdapter()], }); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/copilot/integrate-analytics.prompt.md around lines 287 - 296, The snippet contains stray leading '+' characters making invalid JS; remove the '+' prefixes from the lines that instantiate shareButtonInstance and that call updateOptions inside consentManager.onConsent so the code reads as valid JavaScript: ensure the SocialShareButton instantiation (shareButtonInstance = new SocialShareButton({...})), the consentManager.onConsent("analytics", ...) handler, the call shareButtonInstance.updateOptions({ analytics: true, analyticsPlugins: [new GoogleAnalyticsAdapter()] }) and the GoogleAnalyticsAdapter reference are plain tokens (no '+' characters) and properly formatted.src/social-share-button.js (1)
723-750:⚠️ Potential issue | 🟠 MajorReplace silent analytics
catchblocks with debug-gated warnings via a helper.
_emit()currently swallows failures across all three delivery paths. That keeps the share flow non-fatal, but it also hides broken analytics integrations and makes diagnosis difficult.Proposed fix
+ _debugWarn(message, err) { + if (!this.options.debug) return; + // eslint-disable-next-line no-console + console.warn(`[SocialShareButton Analytics] ${message}`, err); + } + _emit(eventName, interactionType, extra = {}) { @@ if (typeof window !== 'undefined' && typeof CustomEvent !== 'undefined') { try { const domEvent = new CustomEvent('social-share', { @@ const el = this._getContainer(); (el || document).dispatchEvent(domEvent); - } catch (_) {} + } catch (err) { + this._debugWarn('CustomEvent dispatch failed', err); + } } @@ if (typeof this.options.onAnalytics === 'function') { try { this.options.onAnalytics(payload); - } catch (_) {} + } catch (err) { + this._debugWarn('onAnalytics callback failed', err); + } } @@ for (const plugin of this.options.analyticsPlugins) { if (plugin && typeof plugin.track === 'function') { try { plugin.track(payload); - } catch (_) {} + } catch (err) { + this._debugWarn('analytics plugin.track failed', err); + } } } } }Based on learnings: In
src/social-share-button.js, emptycatchblocks in_emit()should be replaced with debug-conditional warnings, and debug console usage should be centralized through a helper.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/social-share-button.js` around lines 723 - 750, The _emit() method currently swallows all exceptions in its three delivery paths (CustomEvent dispatch, this.options.onAnalytics callback, and each plugin.track in this.options.analyticsPlugins); create a centralized debug helper (e.g., _debugWarn or warnAnalytics) on the class that accepts a contextual message and an Error and only logs a console.warn when debugging is enabled, then replace every empty catch block inside _emit() to call that helper with a clear message (e.g., "social-share: failed to dispatch event", "social-share: onAnalytics threw", "social-share: plugin.track threw" along with plugin identity when available), preserving the non-fatal behavior but surface the error details for diagnosis.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/copilot/integrate-social-share-button.prompt.md:
- Around line 28-33: Add a new "Method 4 — Web Component" entry that documents
using the native <social-share-button> web component and explicitly instructs
how to obtain the new wrapper/source file (e.g., link to the package repo or the
specific distribution file in the new PR, or how to import it from the npm
package) and update the existing CDN guidance in "Method 1" to avoid referencing
legacy CDN URLs by including a note that older CDN releases do not contain the
new wrapper; reference the existing headings "Method 1 — CDN (Recommended)",
"Method 2 — npm", and "Method 3 — React Wrapper Component (Optional)" so the new
method sits alongside them and ensure the prompt tells users exactly where to
fetch the new wrapper file and the import/usage snippet for
<social-share-button>.
In `@README.md`:
- Around line 85-93: Add a new "Web Component Integration" section to the README
that explains how to load the web-component bundle by referencing
src/social-share-button-webcomponent.js (e.g., via CDN link to that specific
file) and show a usage snippet with the <social-share-button> element; do not
tell users to use the pre-wrapper tag for this file, and explicitly state that
the webcomponent file must be loaded separately from the core CSS/JS if using
the CDN so users can acquire src/social-share-button-webcomponent.js directly.
In `@src/social-share-button-webcomponent.js`:
- Around line 149-155: The polling interval leaks because
_initSocialShareButton() always starts polling and stores the timer only in a
local variable; add this._checkLibInterval = null in the constructor, change the
local interval to this._checkLibInterval and only start it when this.autoDetect
is true, and in _destroySocialShareButton() call
clearInterval(this._checkLibInterval) and set this._checkLibInterval = null to
stop and release the timer; also add brief inline comments in the constructor,
_initSocialShareButton, and _destroySocialShareButton explaining the timer
lifecycle and the auto-detect guard so future readers understand why the
interval is started/cleared and to avoid reinitializing after disconnect.
- Around line 16-30: Add the missing attributes and implement customClass:
include 'analytics', 'component-id' and 'debug' in the static observedAttributes
array so attributeChangedCallback will fire for them; add a property
getter/setter for customClass on the web component class (mirroring the pattern
used by other props) and map its attribute name in _getOptions() so the
underlying instance receives it; ensure attributeChangedCallback calls
_updateOptions() for these attributes (observedAttributes,
attributeChangedCallback, _getOptions, _updateOptions, customClass, analytics,
component-id, debug).
- Around line 39-42: The button inside the shadow root is unstyled because
external CSS cannot cross the shadow boundary; update the component
initialization (where this._shadow is created via this.attachShadow) to inject
the stylesheet into the shadow DOM — either create and append a <link
rel="stylesheet" href="..."> or load the CSS and append a <style> element into
this._shadow (near the code that sets this._shadow.innerHTML / the container
div) so classes like .social-share-btn and .primary take effect inside the
shadow root.
- Around line 15-16: The module currently extends HTMLElement in the
SocialShareButtonElement class and calls customElements at module load, which
breaks SSR; wrap both uses with runtime guards: only define/extend when typeof
HTMLElement !== 'undefined' (e.g., const SocialShareButtonElement = typeof
HTMLElement !== 'undefined' ? class SocialShareButtonElement extends HTMLElement
{ ... } : class SocialShareButtonElement {} ) and only call
customElements.define/get when typeof customElements !== 'undefined' (e.g., if
(typeof customElements !== 'undefined' &&
!customElements.get('social-share-button'))
customElements.define('social-share-button', SocialShareButtonElement)); ensure
the guarded symbols are SocialShareButtonElement and the customElements checks
so the module can be imported in Node without ReferenceError.
---
Outside diff comments:
In @.github/copilot/integrate-analytics.prompt.md:
- Around line 287-296: The snippet contains stray leading '+' characters making
invalid JS; remove the '+' prefixes from the lines that instantiate
shareButtonInstance and that call updateOptions inside consentManager.onConsent
so the code reads as valid JavaScript: ensure the SocialShareButton
instantiation (shareButtonInstance = new SocialShareButton({...})), the
consentManager.onConsent("analytics", ...) handler, the call
shareButtonInstance.updateOptions({ analytics: true, analyticsPlugins: [new
GoogleAnalyticsAdapter()] }) and the GoogleAnalyticsAdapter reference are plain
tokens (no '+' characters) and properly formatted.
In `@src/social-share-button.js`:
- Around line 723-750: The _emit() method currently swallows all exceptions in
its three delivery paths (CustomEvent dispatch, this.options.onAnalytics
callback, and each plugin.track in this.options.analyticsPlugins); create a
centralized debug helper (e.g., _debugWarn or warnAnalytics) on the class that
accepts a contextual message and an Error and only logs a console.warn when
debugging is enabled, then replace every empty catch block inside _emit() to
call that helper with a clear message (e.g., "social-share: failed to dispatch
event", "social-share: onAnalytics threw", "social-share: plugin.track threw"
along with plugin identity when available), preserving the non-fatal behavior
but surface the error details for diagnosis.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 4d07e849-14a1-49a8-81f8-d92a8b432e2c
📒 Files selected for processing (10)
.github/copilot/integrate-analytics.prompt.md.github/copilot/integrate-social-share-button.prompt.mdREADME.mddocs/client-guide.mdeslint.config.jssrc/social-share-analytics.jssrc/social-share-button-react.jsxsrc/social-share-button-webcomponent.jssrc/social-share-button.csssrc/social-share-button.js
| | Method | When to use | | ||
| | ------------------------------------------------- | ------------------------------------------------------------------------- | | ||
| | **Method 1 — CDN (Recommended)** | Most projects. No build step needed. Load via `<script>` tag. | | ||
| | **Method 2 — npm** | Bundler-based projects (Webpack, Vite, etc.) that prefer `import` syntax. | | ||
| | **Method 3 — React Wrapper Component (Optional)** | Developer explicitly wants a reusable JSX component. | | ||
|
|
There was a problem hiding this comment.
Integration skill is missing a Web Component path and correct wrapper acquisition guidance.
This prompt currently routes users through only three methods and hardcoded legacy CDN URLs, so it cannot generate valid guidance for the new native <social-share-button> wrapper.
Based on learnings: New wrapper/source files are not available in CDN versions that predate the PR; docs/prompts must include explicit acquisition instructions for the new wrapper file.
Also applies to: 52-57
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/copilot/integrate-social-share-button.prompt.md around lines 28 -
33, Add a new "Method 4 — Web Component" entry that documents using the native
<social-share-button> web component and explicitly instructs how to obtain the
new wrapper/source file (e.g., link to the package repo or the specific
distribution file in the new PR, or how to import it from the npm package) and
update the existing CDN guidance in "Method 1" to avoid referencing legacy CDN
URLs by including a note that older CDN releases do not contain the new wrapper;
reference the existing headings "Method 1 — CDN (Recommended)", "Method 2 —
npm", and "Method 3 — React Wrapper Component (Optional)" so the new method sits
alongside them and ensure the prompt tells users exactly where to fetch the new
wrapper file and the import/usage snippet for <social-share-button>.
| ### Via CDN (Recommended) | ||
|
|
||
| ```html | ||
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css"> | ||
| <link | ||
| rel="stylesheet" | ||
| href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css" | ||
| /> | ||
| <script src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js"></script> | ||
| ``` |
There was a problem hiding this comment.
Web Component wrapper is undocumented in installation guidance.
This PR adds a new wrapper, but the README still only shows core JS/CSS loading. Please add a dedicated “Web Component Integration” section with how to load src/social-share-button-webcomponent.js (and a <social-share-button> usage snippet). Also avoid pointing users to a pre-wrapper tag for that file.
Based on learnings: In AOSSIE-Org/SocialShareButton, new wrapper files are not part of older CDN tags; docs must include acquisition instructions for the new wrapper file itself.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@README.md` around lines 85 - 93, Add a new "Web Component Integration"
section to the README that explains how to load the web-component bundle by
referencing src/social-share-button-webcomponent.js (e.g., via CDN link to that
specific file) and show a usage snippet with the <social-share-button> element;
do not tell users to use the pre-wrapper tag for this file, and explicitly state
that the webcomponent file must be loaded separately from the core CSS/JS if
using the CDN so users can acquire src/social-share-button-webcomponent.js
directly.
| class SocialShareButtonElement extends HTMLElement { | ||
| static get observedAttributes() { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "social-share-button-webcomponent.js" -type fRepository: AOSSIE-Org/SocialShareButton
Length of output: 113
🏁 Script executed:
git ls-files | grep -i webcomponentRepository: AOSSIE-Org/SocialShareButton
Length of output: 111
🏁 Script executed:
git ls-files src/ | head -20Repository: AOSSIE-Org/SocialShareButton
Length of output: 246
🏁 Script executed:
git ls-files | grep "social-share" | sortRepository: AOSSIE-Org/SocialShareButton
Length of output: 286
🏁 Script executed:
ls -la src/ 2>/dev/null || echo "src directory check"; git ls-files | grep -E "^src/" | head -30Repository: AOSSIE-Org/SocialShareButton
Length of output: 820
🏁 Script executed:
find . -type f -name "*.js" -o -name "*.jsx" | grep -E "(social|share)" | head -20Repository: AOSSIE-Org/SocialShareButton
Length of output: 210
🏁 Script executed:
pwd && ls -laRepository: AOSSIE-Org/SocialShareButton
Length of output: 1528
🏁 Script executed:
cat README.md 2>/dev/null | head -50 || echo "Checking repo root"; ls -1Repository: AOSSIE-Org/SocialShareButton
Length of output: 2169
🏁 Script executed:
find . -name "*webcomponent*" 2>/dev/nullRepository: AOSSIE-Org/SocialShareButton
Length of output: 113
🏁 Script executed:
ls -1 src/social-share-button* 2>/dev/null || echo "No files found"; git ls-files 2>/dev/null | grep socialRepository: AOSSIE-Org/SocialShareButton
Length of output: 444
🏁 Script executed:
git log --oneline -1 2>/dev/null && git status 2>/dev/null | head -20Repository: AOSSIE-Org/SocialShareButton
Length of output: 368
🏁 Script executed:
git diff --stat HEAD 2>/dev/null | head -30 || echo "Checking working directory"; find . -type f \( -name "*.js" -o -name "*.json" \) -mmin -120 2>/dev/null | head -20Repository: AOSSIE-Org/SocialShareButton
Length of output: 280
🏁 Script executed:
git diff --cached --name-only 2>/dev/null | head -20Repository: AOSSIE-Org/SocialShareButton
Length of output: 54
🏁 Script executed:
git rev-parse --show-toplevel 2>/dev/null && echo "---" && ls -1Repository: AOSSIE-Org/SocialShareButton
Length of output: 261
🏁 Script executed:
ls -la src/ 2>/dev/null && echo "---FILES IN SRC---" && ls -1 src/Repository: AOSSIE-Org/SocialShareButton
Length of output: 815
🏁 Script executed:
wc -l src/social-share-button-webcomponent.js && cat -n src/social-share-button-webcomponent.js | head -50Repository: AOSSIE-Org/SocialShareButton
Length of output: 1647
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | sed -n '1,30p'Repository: AOSSIE-Org/SocialShareButton
Length of output: 1035
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | sed -n '240,250p'Repository: AOSSIE-Org/SocialShareButton
Length of output: 344
🏁 Script executed:
grep -n "HTMLElement\|typeof.*undefined\|window\." src/social-share-button.js | head -20Repository: AOSSIE-Org/SocialShareButton
Length of output: 1012
🏁 Script executed:
grep -r "typeof HTMLElement" src/ || echo "No HTMLElement guard found"Repository: AOSSIE-Org/SocialShareButton
Length of output: 98
🏁 Script executed:
ls -1 src/social-share-button*.jsRepository: AOSSIE-Org/SocialShareButton
Length of output: 138
🏁 Script executed:
head -20 src/social-share-button-react.jsxRepository: AOSSIE-Org/SocialShareButton
Length of output: 714
🏁 Script executed:
grep -n "typeof window\|typeof document\|customElements" src/social-share-button.js | head -15Repository: AOSSIE-Org/SocialShareButton
Length of output: 767
🏁 Script executed:
cat src/social-share-button-webcomponent.jsRepository: AOSSIE-Org/SocialShareButton
Length of output: 5842
🏁 Script executed:
head -40 package.jsonRepository: AOSSIE-Org/SocialShareButton
Length of output: 1168
🏁 Script executed:
cat index.js 2>/dev/null | head -30Repository: AOSSIE-Org/SocialShareButton
Length of output: 54
🏁 Script executed:
grep -E "main|export" package.json | head -10Repository: AOSSIE-Org/SocialShareButton
Length of output: 111
🏁 Script executed:
ls -1 *.js *.mjs 2>/dev/nullRepository: AOSSIE-Org/SocialShareButton
Length of output: 88
🏁 Script executed:
find . -maxdepth 2 -name "index.*" -type f | grep -v node_modulesRepository: AOSSIE-Org/SocialShareButton
Length of output: 84
🏁 Script executed:
python3 << 'EOF'
# Test the proposed SSR guard pattern logic
test_cases = [
{"env": "Browser", "HTMLElement": "function", "customElements": "object"},
{"env": "Node.js", "HTMLElement": "undefined", "customElements": "undefined"},
]
for case in test_cases:
print(f"\nEnvironment: {case['env']}")
# Simulate the proposed fix
html_element_exists = case['HTMLElement'] != 'undefined'
custom_elements_exists = case['customElements'] != 'undefined'
if html_element_exists:
base_class = "HTMLElement"
print(f" BaseHTMLElement = HTMLElement")
else:
base_class = "class {{}}"
print(f" BaseHTMLElement = class {{}}")
# Check if the class definition would work
print(f" class SocialShareButtonElement extends {base_class}: ✓ Would work")
# Check customElements registration
print(f" typeof window !== 'undefined': {html_element_exists}")
print(f" 'customElements' in window: {custom_elements_exists}")
print(f" Would register: {html_element_exists and custom_elements_exists}")
EOFRepository: AOSSIE-Org/SocialShareButton
Length of output: 504
🏁 Script executed:
grep -r "webcomponent\|social-share-button-webcomponent" . --include="*.js" --include="*.json" --include="*.md" 2>/dev/null | grep -v ".git" | head -20Repository: AOSSIE-Org/SocialShareButton
Length of output: 54
🏁 Script executed:
cat package.json | grep -A 10 "scripts"Repository: AOSSIE-Org/SocialShareButton
Length of output: 468
🏁 Script executed:
grep -A 5 -B 5 -i "webcomponent\|ssr\|server" README.md 2>/dev/null | head -30Repository: AOSSIE-Org/SocialShareButton
Length of output: 416
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | sed -n '10,25p'Repository: AOSSIE-Org/SocialShareButton
Length of output: 546
🏁 Script executed:
node -c << 'EOF'
// Test if the proposed fix syntax is valid
const BaseHTMLElement = typeof HTMLElement !== 'undefined' ? HTMLElement : class {};
class SocialShareButtonElement extends BaseHTMLElement {
static get observedAttributes() {
return ['networks', 'url', 'title', 'text'];
}
}
if (
typeof window !== 'undefined' &&
'customElements' in window &&
!window.customElements.get('social-share-button')
) {
window.customElements.define('social-share-button', SocialShareButtonElement);
}
console.log("Syntax check passed");
EOFRepository: AOSSIE-Org/SocialShareButton
Length of output: 54
Guard HTMLElement usage to prevent SSR module loading errors.
Line 15 extends HTMLElement without checking availability. This throws ReferenceError in Node.js/SSR environments where HTMLElement is undefined, making the entire module unimportable on the server. Line 244 also accesses customElements directly without verifying window.
Apply the guard pattern to both the class definition and the registration check:
Recommended fix
+const BaseHTMLElement = typeof HTMLElement !== 'undefined' ? HTMLElement : class {};
-class SocialShareButtonElement extends HTMLElement {
+class SocialShareButtonElement extends BaseHTMLElement {
static get observedAttributes() {-if (typeof window !== 'undefined' && !customElements.get('social-share-button')) {
- customElements.define('social-share-button', SocialShareButtonElement);
+if (
+ typeof window !== 'undefined' &&
+ 'customElements' in window &&
+ !window.customElements.get('social-share-button')
+) {
+ window.customElements.define('social-share-button', SocialShareButtonElement);
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/social-share-button-webcomponent.js` around lines 15 - 16, The module
currently extends HTMLElement in the SocialShareButtonElement class and calls
customElements at module load, which breaks SSR; wrap both uses with runtime
guards: only define/extend when typeof HTMLElement !== 'undefined' (e.g., const
SocialShareButtonElement = typeof HTMLElement !== 'undefined' ? class
SocialShareButtonElement extends HTMLElement { ... } : class
SocialShareButtonElement {} ) and only call customElements.define/get when
typeof customElements !== 'undefined' (e.g., if (typeof customElements !==
'undefined' && !customElements.get('social-share-button'))
customElements.define('social-share-button', SocialShareButtonElement)); ensure
the guarded symbols are SocialShareButtonElement and the customElements checks
so the module can be imported in Node without ReferenceError.
| static get observedAttributes() { | ||
| return [ | ||
| 'url', | ||
| 'title', | ||
| 'description', | ||
| 'hashtags', | ||
| 'via', | ||
| 'platforms', | ||
| 'theme', | ||
| 'button-text', | ||
| 'button-style', | ||
| 'modal-position', | ||
| 'auto-detect', | ||
| ]; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
wc -l src/social-share-button-webcomponent.jsRepository: AOSSIE-Org/SocialShareButton
Length of output: 115
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | head -80Repository: AOSSIE-Org/SocialShareButton
Length of output: 2437
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | sed -n '180,210p'Repository: AOSSIE-Org/SocialShareButton
Length of output: 1202
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | sed -n '130,185p'Repository: AOSSIE-Org/SocialShareButton
Length of output: 1587
🏁 Script executed:
grep -n "get analytics\|set analytics\|get componentId\|set componentId\|get customClass\|set customClass" src/social-share-button-webcomponent.jsRepository: AOSSIE-Org/SocialShareButton
Length of output: 181
🏁 Script executed:
grep -n "customClass\|custom-class" src/social-share-button-webcomponent.jsRepository: AOSSIE-Org/SocialShareButton
Length of output: 54
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | tail -70Repository: AOSSIE-Org/SocialShareButton
Length of output: 2449
Add missing attributes to observedAttributes and implement the customClass property.
analytics, component-id, and debug are defined as properties and passed to _getOptions(), but they're not in observedAttributes (lines 16–30). This prevents post-init attribute updates from triggering attributeChangedCallback() and propagating to the underlying instance via _updateOptions(). Additionally, customClass is missing entirely from the component API—no property getter/setter or attribute mapping in _getOptions() (lines 185–203).
Proposed fix
static get observedAttributes() {
return [
'url',
'title',
'description',
'hashtags',
'via',
'platforms',
'theme',
'button-text',
'button-style',
'modal-position',
'auto-detect',
+ 'analytics',
+ 'component-id',
+ 'debug',
+ 'custom-class',
];
}
@@
+ get customClass() {
+ return this.getAttribute('custom-class') || '';
+ }
+
+ set customClass(value) {
+ if (value == null) {
+ this.removeAttribute('custom-class');
+ } else {
+ this.setAttribute('custom-class', String(value));
+ }
+ }
+
_getOptions() {
return {
container: this._shadow.getElementById('container'),
@@
buttonText: this.buttonText,
+ customClass: this.customClass,
buttonStyle: this.buttonStyle,
modalPosition: this.modalPosition,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/social-share-button-webcomponent.js` around lines 16 - 30, Add the
missing attributes and implement customClass: include 'analytics',
'component-id' and 'debug' in the static observedAttributes array so
attributeChangedCallback will fire for them; add a property getter/setter for
customClass on the web component class (mirroring the pattern used by other
props) and map its attribute name in _getOptions() so the underlying instance
receives it; ensure attributeChangedCallback calls _updateOptions() for these
attributes (observedAttributes, attributeChangedCallback, _getOptions,
_updateOptions, customClass, analytics, component-id, debug).
| if (!this._shadow) { | ||
| this._shadow = this.attachShadow({ mode: 'open' }); | ||
| this._shadow.innerHTML = '<div id="container"></div>'; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | head -60Repository: AOSSIE-Org/SocialShareButton
Length of output: 1897
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | sed -n '35,50p'Repository: AOSSIE-Org/SocialShareButton
Length of output: 552
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | sed -n '180,210p'Repository: AOSSIE-Org/SocialShareButton
Length of output: 1202
🏁 Script executed:
# Search for style-related code in the webcomponent file
rg -n "style|css|inject|shadow" src/social-share-button-webcomponent.js -A 2 -B 2Repository: AOSSIE-Org/SocialShareButton
Length of output: 867
🏁 Script executed:
# Look for the main SocialShareButton class
fd -t f "social-share-button.js" -not -path "*webcomponent*" -not -path "*preact*"Repository: AOSSIE-Org/SocialShareButton
Length of output: 302
🏁 Script executed:
# Check how button styling is handled
rg -n "buttonStyle|style|css" src/social-share-button.js -A 3 -B 1 | head -80Repository: AOSSIE-Org/SocialShareButton
Length of output: 3684
🏁 Script executed:
# Look for innerHTML, createElement patterns that build the button
rg -n "createElement|innerHTML|<button|<div" src/social-share-button.js -B 2 -A 2 | head -100Repository: AOSSIE-Org/SocialShareButton
Length of output: 2426
🏁 Script executed:
# Find CSS or style files
fd -t f "\\.css$" src/Repository: AOSSIE-Org/SocialShareButton
Length of output: 99
🏁 Script executed:
# Search for style injection, appendChild, or insertBefore that might inject CSS
rg "appendChild|insertBefore|style|<style" src/social-share-button.js | grep -i "style\|append\|insert"Repository: AOSSIE-Org/SocialShareButton
Length of output: 1882
🏁 Script executed:
# Check if there's a styles or css reference in the webcomponent file
rg -n "style|css|inject" src/social-share-button-webcomponent.jsRepository: AOSSIE-Org/SocialShareButton
Length of output: 209
🏁 Script executed:
# List all files in src directory
ls -la src/Repository: AOSSIE-Org/SocialShareButton
Length of output: 645
🏁 Script executed:
# Check entire webcomponent file for any style handling
cat -n src/social-share-button-webcomponent.jsRepository: AOSSIE-Org/SocialShareButton
Length of output: 7578
🏁 Script executed:
# Look for stylesheet or style injection patterns
rg -n "link|href|stylesheet|style|css" src/social-share-button-webcomponent.jsRepository: AOSSIE-Org/SocialShareButton
Length of output: 395
🏁 Script executed:
# Check where button and modal are appended - more detailed context
rg -n "appendChild" src/social-share-button.js -B 3 -A 1Repository: AOSSIE-Org/SocialShareButton
Length of output: 466
🏁 Script executed:
# Also check the CSS file to see what styles are defined
head -100 src/social-share-button.cssRepository: AOSSIE-Org/SocialShareButton
Length of output: 1991
The share button won't be styled due to shadow DOM boundary.
The button is rendered inside the shadow root with class names like .social-share-btn, .primary, etc., but the external stylesheet (src/social-share-button.css) cannot cross the shadow DOM boundary. The modal is appended to document.body and will render correctly, but the button inside the shadow DOM remains unstyled.
Inject the stylesheet into the shadow DOM by appending a <style> tag or <link> element during initialization, or copy relevant styles into the shadow root.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/social-share-button-webcomponent.js` around lines 39 - 42, The button
inside the shadow root is unstyled because external CSS cannot cross the shadow
boundary; update the component initialization (where this._shadow is created via
this.attachShadow) to inject the stylesheet into the shadow DOM — either create
and append a <link rel="stylesheet" href="..."> or load the CSS and append a
<style> element into this._shadow (near the code that sets
this._shadow.innerHTML / the container div) so classes like .social-share-btn
and .primary take effect inside the shadow root.
| get autoDetect() { | ||
| return this.getAttribute('auto-detect') === 'true'; | ||
| } | ||
|
|
||
| set autoDetect(value) { | ||
| this.setAttribute('auto-detect', String(value)); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd /tmp/repo 2>/dev/null || cd "$(find /root -type d -name 'SocialShareButton' -o -name 'social-share-button*' 2>/dev/null | head -1)" && pwdRepository: AOSSIE-Org/SocialShareButton
Length of output: 90
🏁 Script executed:
find . -name "*social-share-button-webcomponent.js" -type fRepository: AOSSIE-Org/SocialShareButton
Length of output: 113
🏁 Script executed:
cat -n src/social-share-button-webcomponent.js | head -250Repository: AOSSIE-Org/SocialShareButton
Length of output: 7578
Polling interval leaks past disconnect and auto-detect is ignored.
_initSocialShareButton() always starts polling (lines 208–214) regardless of the auto-detect setting, and the interval handle is stored only as a local variable inside the else-if block. When the component is disconnected, the interval continues running and can initialize an instance after unmount. _destroySocialShareButton() (lines 224–229) does not clear the polling interval.
Add this._checkLibInterval = null to the constructor, store and conditionally clear the interval based on this.autoDetect, and clean up the interval in _destroySocialShareButton(). Also add inline comments explaining the timer lifecycle and auto-detect guard logic per coding guidelines for non-obvious edge cases and cleanup callbacks.
Proposed fix
constructor() {
super();
this._instance = null;
this._shadow = null;
+ this._checkLibInterval = null;
}
@@
_initSocialShareButton() {
+ if (this._instance) return;
+
if (typeof window !== 'undefined' && window.SocialShareButton) {
this._instance = new window.SocialShareButton(this._getOptions());
- } else if (typeof window !== 'undefined') {
- const checkLib = setInterval(() => {
+ } else if (typeof window !== 'undefined' && this.autoDetect) {
+ if (this._checkLibInterval) clearInterval(this._checkLibInterval);
+ this._checkLibInterval = setInterval(() => {
if (window.SocialShareButton) {
- clearInterval(checkLib);
+ clearInterval(this._checkLibInterval);
+ this._checkLibInterval = null;
this._instance = new window.SocialShareButton(this._getOptions());
}
}, 100);
}
}
@@
_destroySocialShareButton() {
+ if (this._checkLibInterval) {
+ clearInterval(this._checkLibInterval);
+ this._checkLibInterval = null;
+ }
if (this._instance && typeof this._instance.destroy === 'function') {
this._instance.destroy();
this._instance = null;
}
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/social-share-button-webcomponent.js` around lines 149 - 155, The polling
interval leaks because _initSocialShareButton() always starts polling and stores
the timer only in a local variable; add this._checkLibInterval = null in the
constructor, change the local interval to this._checkLibInterval and only start
it when this.autoDetect is true, and in _destroySocialShareButton() call
clearInterval(this._checkLibInterval) and set this._checkLibInterval = null to
stop and release the timer; also add brief inline comments in the constructor,
_initSocialShareButton, and _destroySocialShareButton explaining the timer
lifecycle and the auto-detect guard so future readers understand why the
interval is started/cleared and to avoid reinitializing after disconnect.
|
Please resolve the merge conflicts before review. Your PR will only be reviewed by a maintainer after all conflicts have been resolved. 📺 Watch this video to understand why conflicts occur and how to resolve them: |
Addressed Issues:
Fixes #50
Screenshots/Recordings:
N/A (library code only)
Additional Notes:
This PR adds a native Web Component wrapper for SocialShareButton.
Features:
Usage:
Checklist
AI Usage Disclosure
Summary by CodeRabbit
New Features
Documentation
Style