From d3e596f19f849611a86dc2632110a336468c7ded Mon Sep 17 00:00:00 2001 From: Aman kumar vishwakrma <186990161+amankv1234@users.noreply.github.com> Date: Fri, 3 Apr 2026 00:57:53 +0530 Subject: [PATCH 01/18] refactor: improve error handling and fix demo page structure - Added try-catch blocks to createButton and _getContainer to handle invalid CSS selectors. - Improved fallbackCopy error visibility by logging to _debugWarn. - Fixed HTML syntax error in index.html (removed stray closing div). - Removed duplicate CTA section in index.html for cleaner code. - Ran project-wide formatting and linting. Closes #132 --- CONTRIBUTING.md | 1 + README.md | 1 - docs/Roadmap.md | 213 ++--- eslint.config.js | 20 +- index.html | 1321 ++++++++++++++-------------- landing-page/README.md | 1 + landing-page/src/app/globals.css | 7 +- src/social-share-analytics.js | 2 +- src/social-share-button-preact.jsx | 20 +- src/social-share-button-react.jsx | 78 +- src/social-share-button.css | 18 +- src/social-share-button.js | 29 +- 12 files changed, 845 insertions(+), 866 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee20f27..04b5fea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -146,6 +146,7 @@ Push your branch: ### Code Quality Tools We use ESLint for linting and Prettier for formatting. Please run these before submitting a PR: + - `npm run lint` — Check for code quality and style issues. - `npm run format` — Automatically format your code to project standards. - `npm run format:check` — Verify that files are correctly formatted. diff --git a/README.md b/README.md index 34933c9..d9d6179 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,6 @@ Lightweight social sharing component for web applications. Zero dependencies, fr [![npm version](https://img.shields.io/npm/v/social-share-button-aossie.svg)](https://www.npmjs.com/package/social-share-button-aossie) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE) - --- ## Features diff --git a/docs/Roadmap.md b/docs/Roadmap.md index 98ae879..bee023d 100644 --- a/docs/Roadmap.md +++ b/docs/Roadmap.md @@ -1,7 +1,7 @@ # 🚀 SocialShareButton — Project Roadmap > **Version:** 2.0 Draft -> **Status:** Living Document +> **Status:** Living Document --- @@ -27,23 +27,23 @@ This section is the ground truth before any planning. ### ✅ What Already Exists -| Feature | Status | Notes | -|---|---|---| -| CDN distribution (jsDelivr) | ✅ | `v1.0.3` | -| npm package | ✅ | Published as `social-share-button-aossie` (unscoped) | -| 7 share platforms | ✅ | WhatsApp, Facebook, X, LinkedIn, Telegram, Reddit, Email | -| `onShare` callback | ✅ | `(platform, url) => {}` | -| `onCopy` callback | ✅ | `(url) => {}` | -| `theme: 'dark' \| 'light'` | ✅ | Basic two-mode theming | -| `buttonColor` / `buttonHoverColor` | ✅ | Programmatic color overrides | -| `customClass` | ✅ | Escape hatch for custom CSS | -| `modalPosition` | ✅ | Modal placement config | -| `updateOptions()` | ✅ | SPA dynamic URL updates | -| React wrapper | ✅ | Exists as `src/social-share-button-react.jsx` (copy-paste only) | -| TypeScript types | ❌ | None shipped | -| Scoped npm package | ❌ | Not yet (`@social-share/core` etc.) | -| Framework packages | ❌ | No installable Vue / Qwik / Solid packages | -| Proper CSS build artifact | ❌ | CSS imported from `src/` path — breaks in most bundlers | +| Feature | Status | Notes | +| ---------------------------------- | ------ | --------------------------------------------------------------- | +| CDN distribution (jsDelivr) | ✅ | `v1.0.3` | +| npm package | ✅ | Published as `social-share-button-aossie` (unscoped) | +| 7 share platforms | ✅ | WhatsApp, Facebook, X, LinkedIn, Telegram, Reddit, Email | +| `onShare` callback | ✅ | `(platform, url) => {}` | +| `onCopy` callback | ✅ | `(url) => {}` | +| `theme: 'dark' \| 'light'` | ✅ | Basic two-mode theming | +| `buttonColor` / `buttonHoverColor` | ✅ | Programmatic color overrides | +| `customClass` | ✅ | Escape hatch for custom CSS | +| `modalPosition` | ✅ | Modal placement config | +| `updateOptions()` | ✅ | SPA dynamic URL updates | +| React wrapper | ✅ | Exists as `src/social-share-button-react.jsx` (copy-paste only) | +| TypeScript types | ❌ | None shipped | +| Scoped npm package | ❌ | Not yet (`@social-share/core` etc.) | +| Framework packages | ❌ | No installable Vue / Qwik / Solid packages | +| Proper CSS build artifact | ❌ | CSS imported from `src/` path — breaks in most bundlers | ### ⚠️ Known Issues to Fix Before Any New Features @@ -108,13 +108,13 @@ social-share-button/ ← Turborepo monorepo root ### Layer Responsibilities -| Layer | Package | Responsibility | -|---|---|---| -| Core Engine | `@social-share/core` | Platform logic, URL building, config validation | -| Analytics | `@social-share/analytics` | Event emission, consent, adapter routing | -| Theme | `@social-share/theme` | CSS tokens, presets, Theme Designer, export | -| Framework Wrappers | `@social-share/react` etc. | Framework-specific components using core | -| CDN Build | `apps/cdn-build` | Bundles core + wrappers into single distributable | +| Layer | Package | Responsibility | +| ------------------ | -------------------------- | ------------------------------------------------- | +| Core Engine | `@social-share/core` | Platform logic, URL building, config validation | +| Analytics | `@social-share/analytics` | Event emission, consent, adapter routing | +| Theme | `@social-share/theme` | CSS tokens, presets, Theme Designer, export | +| Framework Wrappers | `@social-share/react` etc. | Framework-specific components using core | +| CDN Build | `apps/cdn-build` | Bundles core + wrappers into single distributable | --- @@ -122,7 +122,7 @@ social-share-button/ ← Turborepo monorepo root --- -### ✅ Phase 0 — Stabilization *(Now — before any refactoring)* +### ✅ Phase 0 — Stabilization _(Now — before any refactoring)_ **Goal:** Fix the broken npm package experience and document the full API surface. No new features. @@ -181,6 +181,7 @@ export function executeShare(platform: Platform, config: ShareConfig): void { .. **Goal:** Replace the copy-paste React wrapper with installable framework packages. React first since it already exists as `.jsx`. **Priority order:** + 1. `@social-share/react` — replaces `src/social-share-button-react.jsx` 2. `@social-share/vue` — Composition API component 3. `@social-share/qwik` — Resumable, SSR-safe (open issue) @@ -191,26 +192,27 @@ export function executeShare(platform: Platform, config: ShareConfig): void { .. ```typescript interface SocialShareButtonProps { - url?: string; // default: window.location.href - title?: string; // default: document.title + url?: string; // default: window.location.href + title?: string; // default: document.title description?: string; hashtags?: string[]; via?: string; platforms?: Platform[]; buttonText?: string; - buttonStyle?: 'default' | 'primary' | 'compact' | 'icon-only'; - buttonColor?: string; // existing API - buttonHoverColor?: string; // existing API - customClass?: string; // existing API - theme?: 'dark' | 'light' | ThemeTokens; // string shorthand still works - analytics?: AnalyticsConfig; // Phase 3 + buttonStyle?: "default" | "primary" | "compact" | "icon-only"; + buttonColor?: string; // existing API + buttonHoverColor?: string; // existing API + customClass?: string; // existing API + theme?: "dark" | "light" | ThemeTokens; // string shorthand still works + analytics?: AnalyticsConfig; // Phase 3 componentId?: string; - onShare?: (platform: Platform, url: string) => void; // same signature as today - onCopy?: (url: string) => void; // same signature as today + onShare?: (platform: Platform, url: string) => void; // same signature as today + onCopy?: (url: string) => void; // same signature as today } ``` **Migration for existing React wrapper users:** + ```tsx // Before (copy-paste) import { SocialShareButton } from "./components/SocialShareButton"; @@ -226,7 +228,7 @@ import { SocialShareButton } from "@social-share/react"; --- -### 🔬 Phase 3 — Analytics Module +### 🔬 Phase 3 — Analytics Module **Goal:** Ship `@social-share/analytics` — a privacy-first, pluggable analytics layer that uses the existing `onShare` / `onCopy` callbacks as its internal trigger mechanism. @@ -234,25 +236,25 @@ import { SocialShareButton } from "@social-share/react"; ```typescript // Path 1: DOM Events — zero config, works with any analytics tool -document.addEventListener('ssb:share', (e) => console.log(e.detail)); -document.addEventListener('ssb:copy', (e) => console.log(e.detail)); -document.addEventListener('ssb:modal_open', (e) => console.log(e.detail)); -document.addEventListener('ssb:modal_close', (e) => console.log(e.detail)); +document.addEventListener("ssb:share", (e) => console.log(e.detail)); +document.addEventListener("ssb:copy", (e) => console.log(e.detail)); +document.addEventListener("ssb:modal_open", (e) => console.log(e.detail)); +document.addEventListener("ssb:modal_close", (e) => console.log(e.detail)); // Path 2: Single callback hook — simplest npm integration new SocialShareButton({ analytics: { - onEvent: (event: SSBEvent) => myAnalytics.track(event.name, event.data) - } + onEvent: (event: SSBEvent) => myAnalytics.track(event.name, event.data), + }, }); // Path 3: Named adapter — built-in wiring for popular tools -import { GA4Adapter } from '@social-share/analytics/adapters/ga4'; +import { GA4Adapter } from "@social-share/analytics/adapters/ga4"; new SocialShareButton({ analytics: { - adapter: new GA4Adapter({ measurementId: 'G-XXXXXXXX' }) - } + adapter: new GA4Adapter({ measurementId: "G-XXXXXXXX" }), + }, }); ``` @@ -260,31 +262,31 @@ new SocialShareButton({ ```typescript interface SSBEvent { - name: 'ssb:share' | 'ssb:copy' | 'ssb:modal_open' | 'ssb:modal_close'; + name: "ssb:share" | "ssb:copy" | "ssb:modal_open" | "ssb:modal_close"; platform?: Platform; - componentId?: string; // developer-defined identifier + componentId?: string; // developer-defined identifier url: string; timestamp: number; - sessionId: string; // anonymous, ephemeral, never persisted + sessionId: string; // anonymous, ephemeral, never persisted } ``` #### Built-in Adapters -| Adapter | Notes | -|---|---| -| `GA4Adapter` | `gtag('event', ...)` — no PII sent | -| `MixpanelAdapter` | `mixpanel.track()` — requires Mixpanel loaded | -| `SegmentAdapter` | `analytics.track()` — wraps Segment's standard API | -| `PlausibleAdapter` | `plausible()` custom event — cookieless by default | -| `PostHogAdapter` | `posthog.capture()` — EU cloud + self-hosted compatible | -| `CustomAdapter` | Extend `BaseAdapter`, implement `track(event: SSBEvent): void` | +| Adapter | Notes | +| ------------------ | -------------------------------------------------------------- | +| `GA4Adapter` | `gtag('event', ...)` — no PII sent | +| `MixpanelAdapter` | `mixpanel.track()` — requires Mixpanel loaded | +| `SegmentAdapter` | `analytics.track()` — wraps Segment's standard API | +| `PlausibleAdapter` | `plausible()` custom event — cookieless by default | +| `PostHogAdapter` | `posthog.capture()` — EU cloud + self-hosted compatible | +| `CustomAdapter` | Extend `BaseAdapter`, implement `track(event: SSBEvent): void` | #### Privacy Controls ```typescript -SocialShareButton.analytics.enable(); // call after consent granted -SocialShareButton.analytics.disable(); // opt-out / consent withdrawn +SocialShareButton.analytics.enable(); // call after consent granted +SocialShareButton.analytics.disable(); // opt-out / consent withdrawn SocialShareButton.analytics.isEnabled(); // boolean SocialShareButton.analytics.debug(true); // log to console, don't send ``` @@ -298,7 +300,7 @@ SocialShareButton.analytics.debug(true); // log to console, don't send --- -### 🎨 Phase 4 — Theme System + Theme Designer +### 🎨 Phase 4 — Theme System + Theme Designer **Goal:** Extend existing `dark` / `light` theming into a full CSS-variable-based system with an interactive Theme Designer. All existing `theme`, `buttonColor`, `buttonHoverColor`, `customClass` options remain fully supported. @@ -311,7 +313,7 @@ SocialShareButton.analytics.debug(true); // log to console, don't send --ssb-btn-bg: #1da1f2; --ssb-btn-bg-hover: #0d8fd9; --ssb-btn-radius: 6px; - --ssb-btn-shadow: 0 2px 8px rgba(0,0,0,0.12); + --ssb-btn-shadow: 0 2px 8px rgba(0, 0, 0, 0.12); /* Per-platform icon colors */ --ssb-icon-twitter: #1da1f2; @@ -327,7 +329,7 @@ SocialShareButton.analytics.debug(true); // log to console, don't send --ssb-modal-animation-speed: 200ms; --ssb-font-family: system-ui, sans-serif; - --ssb-shape: rounded; /* rounded | pill | square */ + --ssb-shape: rounded; /* rounded | pill | square */ } ``` @@ -336,6 +338,7 @@ SocialShareButton.analytics.debug(true); // log to console, don't send Hosted at `apps/playground`. **Controls:** + - Colors & Gradients — solid + gradient builder per button - Shapes — rounded / pill / square - Border — width, color, style @@ -344,6 +347,7 @@ Hosted at `apps/playground`. - Font family, shadow intensity, hover effect selector **Export formats:** + - CSS variables block - `.json` theme file (SDK-importable) - Shareable URL (theme as URL params) @@ -369,38 +373,41 @@ import myTheme from './my-theme.json'; // from Theme Designer **Goal:** CDN and SDK reach full feature parity. Complete all planned server-side and CMS integrations. **CDN feature parity:** + - Bundle includes analytics + theming (opt-in at build config level) - Config via `data-ssb-*` HTML attributes or `window.SocialShareButtonConfig` - SRI hash generation in CI, hosted on jsDelivr + unpkg **Platform integrations:** -| Integration | Delivery | Issue Status | -|---|---|---| -| Remix | `@social-share/react` + SSR guide | 🟡 Open | -| Solid.js | `@social-share/solid` | 🟡 Open | -| Rails | Gem wrapper + CDN tag helper | 🟡 Open | -| Django | Template tag + CDN | 🟡 Open | -| Laravel | Blade component + CDN | 🟡 Open | -| WordPress | Plugin (CDN-backed) | 🟡 Open | -| Hugo | Shortcode + CDN | 🟡 Open | -| Jekyll | Include template + CDN | 🟡 Open | -| Web Components (Lit) | `@social-share/wc` | 🟡 Open | -| Alpine.js | `x-data` binding guide + CDN | 🟡 Open | +| Integration | Delivery | Issue Status | +| -------------------- | --------------------------------- | ------------ | +| Remix | `@social-share/react` + SSR guide | 🟡 Open | +| Solid.js | `@social-share/solid` | 🟡 Open | +| Rails | Gem wrapper + CDN tag helper | 🟡 Open | +| Django | Template tag + CDN | 🟡 Open | +| Laravel | Blade component + CDN | 🟡 Open | +| WordPress | Plugin (CDN-backed) | 🟡 Open | +| Hugo | Shortcode + CDN | 🟡 Open | +| Jekyll | Include template + CDN | 🟡 Open | +| Web Components (Lit) | `@social-share/wc` | 🟡 Open | +| Alpine.js | `x-data` binding guide + CDN | 🟡 Open | CI smoke test per integration: spin up minimal app, assert button renders and emits share event. --- -### ⚡ Phase 6 — Advanced Features & Ecosystem +### ⚡ Phase 6 — Advanced Features & Ecosystem **Accessibility:** + - Full ARIA — `role="button"`, `aria-label`, `aria-expanded` on modal - Keyboard navigation — Tab, Enter, Escape - `prefers-reduced-motion` support (maps to `--ssb-modal-animation-speed: 0ms`) - WCAG 2.1 AA tested with axe-core in CI **Performance:** + - CDN bundle: target < 8KB gzipped - npm packages: tree-shakeable — twitter-only import ~1KB - CSS: single `@layer` block, no `@import` chains @@ -409,22 +416,24 @@ CI smoke test per integration: spin up minimal app, assert button renders and em ```typescript SocialShareButton.registerPlatform({ - id: 'bluesky', - label: 'Bluesky', + id: "bluesky", + label: "Bluesky", icon: BlueskyIcon, buildURL: (config) => `https://bsky.app/intent/compose?text=${config.title} ${config.url}`, }); ``` **Native Web Share API:** + ```typescript new SocialShareButton({ - preferNativeShare: 'mobile-only', // true | false | 'mobile-only' + preferNativeShare: "mobile-only", // true | false | 'mobile-only' }); // Falls back to custom modal when navigator.share() is unavailable ``` **Monorepo tooling maturity:** + - Changesets-based automated releases via GitHub Actions - Per-package changelogs - Canary / beta release channel @@ -434,20 +443,20 @@ new SocialShareButton({ ## 🤝 Contribution Opportunities -| Area | Skills Needed | Phase | -|---|---|---| -| Fix CSS export path + `exports` field | npm packaging | 0 | -| Write `.d.ts` TypeScript declarations | TypeScript | 0 | -| Core engine extraction | TypeScript, DOM APIs | 1 | -| Turborepo + pnpm workspace setup | Monorepo tooling | 1 | -| `@social-share/react` (from existing jsx) | React | 2 | -| `@social-share/vue` / `solid` / `qwik` | Vue / Solid / Qwik | 2 | -| Analytics adapters | GA4 / PostHog / Segment APIs | 3 | -| Theme Designer UI | React, CSS variables | 4 | -| CMS / server-side integrations | Rails / Django / Laravel / WP | 5 | -| Accessibility audit | WCAG, axe-core | 6 | -| Docs site | Next.js, MDX | Ongoing | -| CI/CD pipelines | GitHub Actions, Changesets | Ongoing | +| Area | Skills Needed | Phase | +| ----------------------------------------- | ----------------------------- | ------- | +| Fix CSS export path + `exports` field | npm packaging | 0 | +| Write `.d.ts` TypeScript declarations | TypeScript | 0 | +| Core engine extraction | TypeScript, DOM APIs | 1 | +| Turborepo + pnpm workspace setup | Monorepo tooling | 1 | +| `@social-share/react` (from existing jsx) | React | 2 | +| `@social-share/vue` / `solid` / `qwik` | Vue / Solid / Qwik | 2 | +| Analytics adapters | GA4 / PostHog / Segment APIs | 3 | +| Theme Designer UI | React, CSS variables | 4 | +| CMS / server-side integrations | Rails / Django / Laravel / WP | 5 | +| Accessibility audit | WCAG, axe-core | 6 | +| Docs site | Next.js, MDX | Ongoing | +| CI/CD pipelines | GitHub Actions, Changesets | Ongoing | > 💡 Phase 0 tasks are labeled `good-first-issue` and require no monorepo knowledge — ideal starting point for new contributors. @@ -465,16 +474,16 @@ new SocialShareButton({ ## 📊 Distribution Strategy -| Path | Audience | Package | Status | -|---|---|---|---| -| CDN (` - + - - + }); + + + + \ No newline at end of file diff --git a/landing-page/README.md b/landing-page/README.md index f6ebec7..e393b15 100644 --- a/landing-page/README.md +++ b/landing-page/README.md @@ -9,6 +9,7 @@ cd landing-page npm install npm run dev ``` + ## Build ```bash diff --git a/landing-page/src/app/globals.css b/landing-page/src/app/globals.css index c357f40..216b14e 100644 --- a/landing-page/src/app/globals.css +++ b/landing-page/src/app/globals.css @@ -3,7 +3,8 @@ @tailwind utilities; @layer base { - .dark, .dark:root { + .dark, + .dark:root { --background: 0 0% 5%; /* Very dark gray/black #0d0d0d */ --foreground: 0 0% 98%; --primary: 48 100% 50%; /* #FFCC00 */ @@ -28,8 +29,6 @@ --card-foreground: 0 0% 0%; --border: 0 0% 0%; } - - } @layer base { @@ -45,7 +44,7 @@ .text-balance { text-wrap: balance; } - + .hide-scrollbar::-webkit-scrollbar { display: none; } diff --git a/src/social-share-analytics.js b/src/social-share-analytics.js index 8032a50..0caf0d7 100644 --- a/src/social-share-analytics.js +++ b/src/social-share-analytics.js @@ -287,4 +287,4 @@ if (typeof module !== "undefined" && module.exports) { if (typeof window !== "undefined") { window.SocialShareAnalytics = adapters; -} \ No newline at end of file +} diff --git a/src/social-share-button-preact.jsx b/src/social-share-button-preact.jsx index 012e66f..3d9b7cf 100644 --- a/src/social-share-button-preact.jsx +++ b/src/social-share-button-preact.jsx @@ -1,6 +1,6 @@ import { useEffect, useRef } from "preact/hooks"; - /** +/** * SocialShareButton Preact Wrapper * * Provides a lightweight Preact functional component that wraps the core @@ -26,7 +26,7 @@ export default function SocialShareButton({ onCopy = null, buttonStyle = "default", modalPosition = "center", - + // Analytics props — the library emits events but never collects data itself. analytics = true, onAnalytics = null, // (payload) => void hook @@ -36,10 +36,10 @@ export default function SocialShareButton({ }) { // DOM reference to the container where the button will be injected const containerRef = useRef(null); - + // Reference to the vanilla JS class instance const shareButtonRef = useRef(null); - + // Storage for the latest options to avoid stale closures during async initialization const latestOptionsRef = useRef(null); @@ -74,9 +74,9 @@ export default function SocialShareButton({ /** * Initialization Effect - * + * * Handles the setup of the vanilla JS instance once the component mounts. - * Includes a polling mechanism to wait for the core library if it's loaded + * Includes a polling mechanism to wait for the core library if it's loaded * asynchronously (e.g., via a CDN script tag). */ useEffect(() => { @@ -131,12 +131,12 @@ export default function SocialShareButton({ /** * Update Effect - * - * Synchronizes prop changes from Preact down to the vanilla JS instance + * + * Synchronizes prop changes from Preact down to the vanilla JS instance * without re-mounting the entire component. */ - - // Stringify array dependencies to prevent unnecessary re-runs when + + // Stringify array dependencies to prevent unnecessary re-runs when // parent components pass fresh array literals on every render. const hashtagsDep = JSON.stringify(hashtags); const platformsDep = JSON.stringify(platforms); diff --git a/src/social-share-button-react.jsx b/src/social-share-button-react.jsx index 24eb3b2..45ac8f8 100644 --- a/src/social-share-button-react.jsx +++ b/src/social-share-button-react.jsx @@ -3,8 +3,8 @@ import { useEffect, useRef } from "react"; /** * SocialShareButton React Wrapper * - * Provides a React functional component that wraps the core SocialShareButton - * vanilla JS library. Handles lifecycle, dynamic updates, and provides + * Provides a React functional component that wraps the core SocialShareButton + * vanilla JS library. Handles lifecycle, dynamic updates, and provides * sensible defaults for all sharing options. */ export const SocialShareButton = ({ @@ -21,7 +21,7 @@ export const SocialShareButton = ({ onCopy = null, buttonStyle = "default", modalPosition = "center", - + // Analytics: library emits events but never collects data analytics = true, onAnalytics = null, // Event callback @@ -31,7 +31,7 @@ export const SocialShareButton = ({ }) => { // DOM reference for the injection target const containerRef = useRef(null); - + // Reference to the vanilla JS class instance const shareButtonRef = useRef(null); @@ -41,52 +41,52 @@ export const SocialShareButton = ({ /** * Initialization Effect - * + * * Sets up the vanilla JS component once the React component mounts. * Includes a safe check for the global SocialShareButton class. */ useEffect(() => { - if (containerRef.current && !shareButtonRef.current) { - if (typeof window !== "undefined" && window.SocialShareButton) { - shareButtonRef.current = new window.SocialShareButton({ - container: containerRef.current, - url: currentUrl, - title: currentTitle, - description, - hashtags, - via, - platforms, - theme, - buttonText, - customClass, - onShare, - onCopy, - buttonStyle, - modalPosition, - analytics, - onAnalytics, - analyticsPlugins, - componentId, - debug, - }); - } + if (containerRef.current && !shareButtonRef.current) { + if (typeof window !== "undefined" && window.SocialShareButton) { + shareButtonRef.current = new window.SocialShareButton({ + container: containerRef.current, + url: currentUrl, + title: currentTitle, + description, + hashtags, + via, + platforms, + theme, + buttonText, + customClass, + onShare, + onCopy, + buttonStyle, + modalPosition, + analytics, + onAnalytics, + analyticsPlugins, + componentId, + debug, + }); } + } - return () => { - if (shareButtonRef.current) { - shareButtonRef.current.destroy(); - shareButtonRef.current = null; - } - }; - }, []); + return () => { + if (shareButtonRef.current) { + shareButtonRef.current.destroy(); + shareButtonRef.current = null; + } + }; + }, []); /** * Update Effect - * - * Synchronizes React prop changes with the underlying vanilla JS instance + * + * Synchronizes React prop changes with the underlying vanilla JS instance * without re-mounting the entire component. */ - + useEffect(() => { if (shareButtonRef.current) { // Use the library's built-in update method diff --git a/src/social-share-button.css b/src/social-share-button.css index d42c10b..0609839 100644 --- a/src/social-share-button.css +++ b/src/social-share-button.css @@ -238,7 +238,6 @@ background: rgba(255, 255, 255, 0.4); } - /* Individual Platform Button */ .social-share-platform-btn { display: flex; @@ -255,8 +254,8 @@ } .social-share-platform-btn:hover { - transform: scale(1.05); - } + transform: scale(1.05); +} .social-share-platform-btn:active { transform: scale(0.95); @@ -278,10 +277,10 @@ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); } -.social-share-platform-icon svg { +.social-share-platform-icon svg { width: 28px; - height: 28px; - } + height: 28px; +} .social-share-platform-btn span { font-size: 12px; @@ -375,7 +374,6 @@ background: #00b857; } - /* ----------------------------------------------------------------------------- RESPONSIVE OVERRIDES ----------------------------------------------------------------------------- */ @@ -389,11 +387,10 @@ } /* Snap modal to bottom on mobile */ - .social-share-modal-content.bottom { - margin-top: auto; + .social-share-modal-content.bottom { + margin-top: auto; } - .social-share-modal-header { padding: 12px 16px; } @@ -450,7 +447,6 @@ color: #fff; } - /* ----------------------------------------------------------------------------- ACCESSIBILITY & PRINT ----------------------------------------------------------------------------- */ diff --git a/src/social-share-button.js b/src/social-share-button.js index 3905128..2beac7a 100644 --- a/src/social-share-button.js +++ b/src/social-share-button.js @@ -86,10 +86,15 @@ class SocialShareButton { this.button = button; if (this.options.container) { - const container = - typeof this.options.container === "string" - ? document.querySelector(this.options.container) - : this.options.container; + let container = null; + try { + container = + typeof this.options.container === "string" + ? document.querySelector(this.options.container) + : this.options.container; + } catch (error) { + this._debugWarn("Invalid container selector provided", error); + } if (container) { container.appendChild(button); @@ -500,7 +505,8 @@ class SocialShareButton { copyBtn.classList.remove("copied"); this.feedbackTimeout = null; }, 2000); - } catch (_err) { + } catch (error) { + this._debugWarn("Copy to clipboard failed", error); copyBtn.textContent = "Failed"; // Clear any existing feedback timeout @@ -684,9 +690,14 @@ class SocialShareButton { _getContainer() { if (!this.options.container) return null; if (typeof document === "undefined") return null; - return typeof this.options.container === "string" - ? document.querySelector(this.options.container) - : this.options.container; + try { + return typeof this.options.container === "string" + ? document.querySelector(this.options.container) + : this.options.container; + } catch (error) { + this._debugWarn("Invalid container selector provided in _getContainer", error); + return null; + } } /** @@ -799,4 +810,4 @@ if (typeof module !== "undefined" && module.exports) { if (typeof window !== "undefined") { window.SocialShareButton = SocialShareButton; -} \ No newline at end of file +} From 6d7adaa8c770ea0f495c73b057f33a5c1c3f4086 Mon Sep 17 00:00:00 2001 From: Aman kumar vishwakrma <186990161+amankv1234@users.noreply.github.com> Date: Fri, 3 Apr 2026 01:07:34 +0530 Subject: [PATCH 02/18] refactor: improve error handling and clean up demo page structure - Implemented defensive try-catch blocks for container selector resolution. - Refactored createButton() to deduplicate logic via _getContainer() helper. - Enhanced fallbackCopy() to log clipboard errors using the _debugWarn helper. - Fixed a SyntaxError in index.html and removed a redundant CTA section. - Ran project-wide formatting and linting for full code consistency. Closes #132 --- src/social-share-button.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/social-share-button.js b/src/social-share-button.js index 2beac7a..13cb56f 100644 --- a/src/social-share-button.js +++ b/src/social-share-button.js @@ -85,20 +85,10 @@ class SocialShareButton { `; this.button = button; - if (this.options.container) { - let container = null; - try { - container = - typeof this.options.container === "string" - ? document.querySelector(this.options.container) - : this.options.container; - } catch (error) { - this._debugWarn("Invalid container selector provided", error); - } + const container = this._getContainer(); - if (container) { - container.appendChild(button); - } + if (container) { + container.appendChild(button); } } From ea1aa4805973ae98caba924fc7ec19505a8720a3 Mon Sep 17 00:00:00 2001 From: Aman kumar vishwakrma <186990161+amankv1234@users.noreply.github.com> Date: Fri, 3 Apr 2026 01:21:54 +0530 Subject: [PATCH 03/18] refactor: improve error handling and clean up demo page structure - Implemented defensive try-catch blocks for container selector resolution. - Added DOM Element type safety check in _getContainer() to prevent crashes. - Refactored createButton() to deduplicate logic via _getContainer() helper. - Enhanced fallbackCopy() to log clipboard errors using the _debugWarn helper. - Fixed a SyntaxError in index.html and removed a redundant CTA section. - Ran project-wide formatting and linting for full code consistency. Closes #132 --- index.html | 1427 ++++++++++++++++++------------------ src/social-share-button.js | 18 +- 2 files changed, 744 insertions(+), 701 deletions(-) diff --git a/index.html b/index.html index 641b372..a259bcf 100644 --- a/index.html +++ b/index.html @@ -1,776 +1,807 @@ + + + + + SocialShareButton Demo - Modern Social Sharing Component + + + - - - -
-
-

- - SocialShareButton -

-

- A lightweight, modern, and highly customizable social sharing component -

-
- 📦 Zero Dependencies - ⚡ < 10KB - 📱 Mobile Ready - ♿ Accessible - 🎨 Customizable -
-
- - -
-

✨ Key Features

-
-
-
🌐
-

7+ Platforms

-

WhatsApp, Facebook, X, LinkedIn, Telegram, Reddit, Email, Pinterest

-
-
-
🎨
-

Themeable

-

Dark and light themes with full CSS customization

-
-
-
⚙️
-

Framework Agnostic

-

Works with React, Vue, Angular, or vanilla JS

+ display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 20px; + margin-top: 20px; + } + + .demo-item { + background: rgba(0, 0, 0, 0.2); + padding: 20px; + border-radius: 12px; + text-align: center; + } + + .demo-item h3 { + color: #fff; + margin-bottom: 15px; + font-size: 16px; + } + + .demo-item p { + font-size: 13px; + margin-bottom: 15px; + color: rgba(255, 255, 255, 0.8); + } + + .feature-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 20px; + margin-top: 20px; + } + + .feature-card { + background: rgba(0, 0, 0, 0.2); + padding: 20px; + border-radius: 12px; + text-align: center; + } + + .feature-icon { + font-size: 40px; + margin-bottom: 10px; + } + + .feature-card h3 { + color: #fff; + font-size: 16px; + margin-bottom: 10px; + } + + .feature-card p { + font-size: 13px; + color: rgba(255, 255, 255, 0.8); + margin: 0; + } + + .code-block { + position: relative; + background: rgba(0, 0, 0, 0.4); + border-radius: 8px; + padding: 20px; + margin: 20px 0; + overflow-x: auto; + } + + .copy-btn { + position: absolute; + top: 12px; + right: 12px; + background: #667eea; + color: white; + border: none; + border-radius: 6px; + padding: 6px 12px; + font-size: 12px; + cursor: pointer; + transition: all 0.2s ease; + } + + .copy-btn:hover { + background: #5a67d8; + transform: scale(1.05); + } + + .code-block code { + color: #4fd1c5; + font-family: "Courier New", monospace; + font-size: 14px; + line-height: 1.6; + white-space: pre; + } + + .cta-section { + text-align: center; + padding: 40px 20px; + } + + .cta-button { + display: inline-block; + background: #fff; + color: #667eea; + padding: 15px 40px; + border-radius: 30px; + text-decoration: none; + font-weight: 600; + font-size: 16px; + transition: all 0.3s ease; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); + } + + .cta-button:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3); + } + + .cta-buttons { + display: flex; + justify-content: center; + gap: 15px; + flex-wrap: wrap; + } + + .discord-btn { + background: #5865f2; + color: #fff; + } + + .discord-btn:hover { + background: #4752c4; + } + + footer { + text-align: center; + color: rgba(255, 255, 255, 0.8); + padding: 40px 20px; + font-size: 14px; + } + + @media (max-width: 768px) { + h1, + .brand { + font-size: 32px; + } + + .tagline { + font-size: 16px; + } + + .demo-grid { + grid-template-columns: 1fr; + } + } + + + + +
+
+

+ + SocialShareButton +

+

+ A lightweight, modern, and highly customizable social sharing component +

+
+ 📦 Zero Dependencies + ⚡ < 10KB + 📱 Mobile Ready + ♿ Accessible + 🎨 Customizable
-
-
📐
-

Responsive

-

Optimized for all screen sizes

+
+ + +
+

✨ Key Features

+
+
+
🌐
+

7+ Platforms

+

WhatsApp, Facebook, X, LinkedIn, Telegram, Reddit, Email, Pinterest

+
+
+
🎨
+

Themeable

+

Dark and light themes with full CSS customization

+
+
+
⚙️
+

Framework Agnostic

+

Works with React, Vue, Angular, or vanilla JS

+
+
+
📐
+

Responsive

+

Optimized for all screen sizes

+
-
- -
-

🎨 Button Styles

-

Choose from multiple pre-built styles or create your own

-
-
-

Default

-

Clean, minimal design

-
-
-
-

Primary

-

Eye-catching gradient

-
-
-
-

Light Theme

-

Light backgrounds

-
-
-
-

Compact

-

Space-saving variant

-
-
-
-

Icon Only

-

Minimal footprint

-
+ +
+

🎨 Button Styles

+

Choose from multiple pre-built styles or create your own

+
+
+

Default

+

Clean, minimal design

+
+
+
+

Primary

+

Eye-catching gradient

+
+
+
+

Light Theme

+

Light backgrounds

+
+
+
+

Compact

+

Space-saving variant

+
+
+
+

Icon Only

+

Minimal footprint

+
+
-
- -
-

🎨 Custom Button Colors

-

Customize button colors to match your brand palette

-
-
-

Red Theme

-

#f44336 - Material Red

-
-
-
-

Green Theme

-

#10b981 - Emerald Green

-
-
-
-

Blue Theme

-

#3b82f6 - Sky Blue

-
-
-
-

Purple Theme

-

#a855f7 - Custom Purple

-
-
-
-

Orange Theme

-

#f97316 - Vibrant Orange

-
-
-
-

Pink Theme

-

#ec4899 - Hot Pink

-
+ +
+

🎨 Custom Button Colors

+

Customize button colors to match your brand palette

+
+
+

Red Theme

+

#f44336 - Material Red

+
+
+
+

Green Theme

+

#10b981 - Emerald Green

+
+
+
+

Blue Theme

+

#3b82f6 - Sky Blue

+
+
+
+

Purple Theme

+

#a855f7 - Custom Purple

+
+
+
+

Orange Theme

+

#f97316 - Vibrant Orange

+
+
+
+

Pink Theme

+

#ec4899 - Hot Pink

+
+
-
- -
-

🔧 Custom Platform Selection

-

Choose which platforms to display

-
-
-

Professional

-

LinkedIn, X, Email

-
-
-
-

Social Media

-

Facebook, X, Reddit, Pinterest

-
-
-
-

Messaging

-

WhatsApp, Telegram

-
+ +
+

🔧 Custom Platform Selection

+

Choose which platforms to display

+
+
+

Professional

+

LinkedIn, X, Email

+
+
+
+

Social Media

+

Facebook, X, Reddit, Pinterest

+
+
+
+

Messaging

+

WhatsApp, Telegram

+
+
-
- - -
-

🚀 Quick Start

-

Get started in seconds with minimal setup

-
- - - + +
+

🚀 Quick Start

+

Get started in seconds with minimal setup

+ +
+ + + <link rel="stylesheet" href="social-share-button.css"> <script src="social-share-button.js"></script> // Initialize new SocialShareButton({ container: '#share-button', url: 'https://your-website.com', title: 'Check this out!', - description: 'An amazing website' }); + description: 'An amazing website' }); +
-
- - -
-

⚛️ React Integration

-

First-class React support with hooks

-
- - - - import SocialShareButton from 'social-share-button'; function App() { return ( + +
+

⚛️ React Integration

+

First-class React support with hooks

+ +
+ + + + import SocialShareButton from 'social-share-button'; function App() { return ( <SocialShareButton url="https://your-website.com" title="Check this out!" - onShare={(platform) => { console.log('Shared on:', platform); }} /> ); } + onShare={(platform) => { console.log('Shared on:', platform); }} /> ); } +
-
- -
-

⚛️ Preact Integration

-

Step 1: Include CSS and JS via CDN

- -
- - - + +
+

⚛️ Preact Integration

+

Step 1: Include CSS and JS via CDN

+ +
+ + + <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.css"> <script src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.js"></script> -
+
-

Step 2: Import and use the component in a Preact app

+

Step 2: Import and use the component in a Preact app

-
- - - +
+ + + // App.jsx (Preact) import SocialShareButton from './social-share-button-preact'; export default function App() { return ( <SocialShareButton url="https://your-website.com" title="Check this out!" description="An amazing website" theme="dark" buttonText="Share" /> ); } +
+
+ +
+

Ready to Get Started?

+ + View on GitHub → + + + + Join Discord +
-
- -
-

Ready to Get Started?

- - View on GitHub → - - - - Join Discord - -
-
- - - -
-

⚡ Qwik / QwikCity Integration

-

Resumability-optimized wrapper for the fastest performance.

- -
- - - - <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.css"> - <script src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.js"></script> - - - import { component$ } from '@builder.io/qwik'; - import { SocialShareButton } from './social-share-button-qwik'; - - export default component$(() => ( - <SocialShareButton - url="https://your-website.com" - theme="light" - buttonText="Share Now" - buttonStyle="primary" - /> - )); -
-
+ +
+

⚡ Qwik / QwikCity Integration

+

Resumability-optimized wrapper for the fastest performance.

+ +
+ + + + <link rel="stylesheet" + href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.css"> + <script + src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.js"></script> + + + import { component$ } from '@builder.io/qwik'; import { SocialShareButton } from + './social-share-button-qwik'; export default component$(() => ( <SocialShareButton + url="https://your-website.com" theme="light" buttonText="Share Now" + buttonStyle="primary" /> )); +
+
+
+

▲ Next.js Integration

+

Use the component inside a Next.js page

-
-

▲ Next.js Integration

-

Use the component inside a Next.js page

+
+ import SocialShareButton from 'social-share-button'; export default function Home() { + return ( <SocialShareButton url="https://your-website.com" title="Check this out!" + /> ); } +
+
-
- import SocialShareButton from 'social-share-button'; +
+

🟢 Vue / Vite Integration

+

Use inside a Vue component

-export default function Home() { - return ( - <SocialShareButton - url="https://your-website.com" - title="Check this out!" - /> - ); -}
-
-
- -
-

🟢 Vue / Vite Integration

-

Use inside a Vue component

- -
- <template> - <SocialShareButton - url="https://your-website.com" - title="Check this out!" - /> -</template> - -<script setup> -import SocialShareButton from 'social-share-button' -</script> -
-
- -
-

🅰️ Angular Integration

-

Use inside an Angular component template

- -
- <social-share-button - [url]="'https://your-website.com'" - [title]="'Check this out!'" -> -</social-share-button> +
+ <template> <SocialShareButton url="https://your-website.com" title="Check this + out!" /> </template> <script setup> import SocialShareButton from + 'social-share-button' </script> +
+
+ +
+

🅰️ Angular Integration

+

Use inside an Angular component template

+ +
+ <social-share-button [url]="'https://your-website.com'" [title]="'Check this out!'" + > </social-share-button> +
+
+ + +
+

Ready to Get Started?

+ + View on GitHub → + + + + Join Discord + +
-
- - - - -
-

Ready to Get Started?

- - View on GitHub → - - - - Join Discord - -
- -
- -
-

Made with ❤️ by the AOSSIE community

-

- GPL v3 Licensed | - GitHub - | - Issues -

-
- - - + - - - \ No newline at end of file + + + diff --git a/src/social-share-button.js b/src/social-share-button.js index 13cb56f..bfb0de5 100644 --- a/src/social-share-button.js +++ b/src/social-share-button.js @@ -680,14 +680,26 @@ class SocialShareButton { _getContainer() { if (!this.options.container) return null; if (typeof document === "undefined") return null; + + let container = null; try { - return typeof this.options.container === "string" - ? document.querySelector(this.options.container) - : this.options.container; + container = + typeof this.options.container === "string" + ? document.querySelector(this.options.container) + : this.options.container; } catch (error) { this._debugWarn("Invalid container selector provided in _getContainer", error); return null; } + + // Safety check: ensure the resolved value is actually a DOM Element. + // This prevents crashes if a user passes a non-DOM object to the container option. + if (container && !(container instanceof Element || container.nodeType === 1)) { + this._debugWarn("Provided container is not a valid DOM Element", { container }); + return null; + } + + return container; } /** From ee7d77819c0637a8ed92bc5e57885afdd99ba49f Mon Sep 17 00:00:00 2001 From: Aman kumar vishwakrma <186990161+amankv1234@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:23:01 +0530 Subject: [PATCH 04/18] feat: add WordPress integration guide and demo section - Added a new 'WordPress Integration' section to index.html with step-by-step instructions. - Included PHP code snippets for enqueuing assets in unctions.php via standard WordPress hooks (wp_enqueue_scripts, wp_footer). - Implemented copy-to-clipboard functionality for the new code blocks. - Updated README.md to list WordPress as a formally supported platform. Fixes #52, Fixes #112 --- README.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++++---- index.html | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d9d6179..40c5e66 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Lightweight social sharing component for web applications. Zero dependencies, fr - 🌐 Multiple platforms: WhatsApp, Facebook, X, LinkedIn, Telegram, Reddit, Email, Pinterest - 🎯 Zero dependencies - pure vanilla JavaScript -- ⚛️ Framework support: React, Preact, Next.js, Qwik, Vue, Angular, or plain HTML +- ⚛️ Framework support: React, Preact, Next.js, Qwik, Vue, Angular, WordPress or plain HTML - 🔄 Auto-detects current URL and page title - 📱 Fully responsive and mobile-ready - 🎨 Customizable themes (dark/light) @@ -105,9 +105,9 @@ No matter which framework you use, integration always follows the same 3 steps: | Step | What to do | Where | | -------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | -| **1️⃣ Load Library** | Add CSS + JS (CDN links) | Global layout file — `index.html` / `layout.tsx` / `_document.tsx` | -| **2️⃣ Add Container** | Place `
` | The UI component where you want the button to appear | -| **3️⃣ Initialize** | Call `new SocialShareButton({ container: "#share-button" })` | Inside that component, after the DOM is ready (e.g. `useEffect`, `mounted`, `ngAfterViewInit`) | +| **1️⃣ Load Library** | Add CSS + JS (CDN links) | Global layout file — `index.html` / `layout.tsx` / `_document.tsx` / `functions.php` | +| **2️⃣ Add Container** | Place `
` | The UI component or WordPress `wp_footer` hook | +| **3️⃣ Initialize** | Call `new SocialShareButton({ container: "#share-button" })` | Inside that component or WordPress `wp_footer` hook | > 💡 Pick your framework below for the full copy-paste snippet: @@ -486,6 +486,52 @@ export default function Header() { +
+🔷 WordPress + +### Step 1: Enqueue in `functions.php` + +Add the following to your theme's `functions.php` to load the library from CDN: + +```php +function enqueue_social_share_button() { + wp_enqueue_style( + 'social-share-button', + 'https://cdn.jsdelivr.net/npm/social-share-button/dist/social-share-button.css' + ); + wp_enqueue_script( + 'social-share-button', + 'https://cdn.jsdelivr.net/npm/social-share-button/dist/social-share-button.js', + [], + null, + true // Load in footer + ); +} +add_action('wp_enqueue_scripts', 'enqueue_social_share_button'); +``` + +### Step 2: Initialize in `functions.php` (Footer Hook) + +You can use the `wp_footer` hook to inject the container and initialization script: + +```php +function init_social_share_button() { ?> +
+ + + --- ## Configuration diff --git a/index.html b/index.html index a259bcf..c56312f 100644 --- a/index.html +++ b/index.html @@ -476,6 +476,61 @@

⚛️ Preact Integration

+ + +
+

🔷 WordPress Integration

+

Integrate SocialShareButton into your WordPress theme without any extra plugins.

+ +

Step 1: Enqueue the CSS and JS in functions.php

+
+ + + +function enqueue_social_share_button() { + wp_enqueue_style( + 'social-share-button', + 'https://cdn.jsdelivr.net/npm/social-share-button/dist/social-share-button.css' + ); + wp_enqueue_script( + 'social-share-button', + 'https://cdn.jsdelivr.net/npm/social-share-button/dist/social-share-button.js', + [], + null, + true // Load in footer + ); +} +add_action('wp_enqueue_scripts', 'enqueue_social_share_button'); +
+ +

Step 2: Initialize the button in the footer

+
+ + + +function init_social_share_button() { ?> + <div id="share-button"></div> + <script> + new SocialShareButton({ + container: '#share-button', + url: window.location.href, + title: document.title, + theme: 'dark', + buttonText: 'Share' + }); + </script> +<?php } +add_action('wp_footer', 'init_social_share_button'); +
+

Ready to Get Started?

From dd06a624e2adae0019ad90cdc3b37d75c28b92ea Mon Sep 17 00:00:00 2001 From: Aman kumar vishwakrma <186990161+amankv1234@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:37:46 +0530 Subject: [PATCH 05/18] fixed --- index.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index c56312f..167d8c6 100644 --- a/index.html +++ b/index.html @@ -810,8 +810,9 @@

Ready to Get Started?

copyButtons.forEach((button) => { button.addEventListener("click", () => { - const codeBlock = button.closest(".code-block")?.querySelector("code"); - const text = codeBlock ? codeBlock.innerText : ""; + const codeBlockContainer = button.closest(".code-block"); + const codeBlocks = codeBlockContainer ? codeBlockContainer.querySelectorAll("code") : []; + const text = Array.from(codeBlocks).map(code => code.textContent).join("\n"); const originalText = button.textContent; const statusSpan = button.nextElementSibling; From 53d65331c9bbe2fe4c8e21fe468bc69625f0e5ed Mon Sep 17 00:00:00 2001 From: Aman kumar vishwakrma <186990161+amankv1234@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:39:34 +0530 Subject: [PATCH 06/18] fix: escape raw arrow operator in code snippet - Replaced raw => characters with the HTML-escaped => equivalent in the Qwik component code block within index.html. - Resolves potential HTML linting/validation errors caused by raw greater-than signs inside tags. --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 167d8c6..44d9006 100644 --- a/index.html +++ b/index.html @@ -573,7 +573,7 @@

⚡ Qwik / QwikCity Integration

import { component$ } from '@builder.io/qwik'; import { SocialShareButton } from - './social-share-button-qwik'; export default component$(() => ( <SocialShareButton + './social-share-button-qwik'; export default component$(() => ( <SocialShareButton url="https://your-website.com" theme="light" buttonText="Share Now" buttonStyle="primary" /> )); From 4f2dbd4944944d520df89f8320d2098253625c5e Mon Sep 17 00:00:00 2001 From: Aman kumar vishwakrma <186990161+amankv1234@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:40:59 +0530 Subject: [PATCH 07/18] fixed --- index.html | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/index.html b/index.html index 44d9006..2b216df 100644 --- a/index.html +++ b/index.html @@ -618,27 +618,7 @@

🅰️ Angular Integration

- -
-

Ready to Get Started?

- - View on GitHub → - - - Join Discord - -
From 17b04a1997bddac0d718b3f053de4182a8467790 Mon Sep 17 00:00:00 2001 From: Aman kumar vishwakrma <186990161+amankv1234@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:42:51 +0530 Subject: [PATCH 08/18] fix: correct WordPress CDN URLs and wp_footer hook priority - Replaced incorrect npm CDN URLs with the correct jsDelivr + GitHub CDN pointing to AOSSIE-Org/SocialShareButton@v1.0.4 in both index.html and README.md. - Updated wp_footer add_action priority from default (10) to 21 so enqueued footer scripts are printed before initialization runs. - Added a note in README clarifying the package is not published to npm. --- README.md | 13 ++++++++----- index.html | 6 +++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 40c5e66..1c21ae4 100644 --- a/README.md +++ b/README.md @@ -491,17 +491,19 @@ export default function Header() { ### Step 1: Enqueue in `functions.php` -Add the following to your theme's `functions.php` to load the library from CDN: +Add the following to your theme's `functions.php` to load the library directly from this repository via jsDelivr CDN: + +> **Note:** This package is not published to npm. Use the jsDelivr + GitHub CDN link below to load the correct distributable from the [AOSSIE-Org/SocialShareButton](https://github.com/AOSSIE-Org/SocialShareButton) repository. ```php function enqueue_social_share_button() { wp_enqueue_style( 'social-share-button', - 'https://cdn.jsdelivr.net/npm/social-share-button/dist/social-share-button.css' + 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.css' ); wp_enqueue_script( 'social-share-button', - 'https://cdn.jsdelivr.net/npm/social-share-button/dist/social-share-button.js', + 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.js', [], null, true // Load in footer @@ -512,7 +514,7 @@ add_action('wp_enqueue_scripts', 'enqueue_social_share_button'); ### Step 2: Initialize in `functions.php` (Footer Hook) -You can use the `wp_footer` hook to inject the container and initialization script: +Use the `wp_footer` hook with a **priority of 21** to inject the container and initialization script. The priority must be higher than the default (10) so WordPress prints the enqueued footer scripts *before* this function runs: ```php function init_social_share_button() { ?> @@ -527,7 +529,8 @@ function init_social_share_button() { ?> }); diff --git a/index.html b/index.html index 2b216df..79e8ea5 100644 --- a/index.html +++ b/index.html @@ -494,11 +494,11 @@

🔷 WordPress Integration

function enqueue_social_share_button() { wp_enqueue_style( 'social-share-button', - 'https://cdn.jsdelivr.net/npm/social-share-button/dist/social-share-button.css' + 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.css' ); wp_enqueue_script( 'social-share-button', - 'https://cdn.jsdelivr.net/npm/social-share-button/dist/social-share-button.js', + 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.js', [], null, true // Load in footer @@ -528,7 +528,7 @@

🔷 WordPress Integration

}); </script> <?php } -add_action('wp_footer', 'init_social_share_button');
+add_action('wp_footer', 'init_social_share_button', 21);
From d3c30148ac814f5fc55bed5df544fb958b6dcf7e Mon Sep 17 00:00:00 2001 From: Aman kumar vishwakrma <186990161+amankv1234@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:45:04 +0530 Subject: [PATCH 09/18] fix: silence intentional catch block in fallback copy - Removed his._debugWarn logging inside the allbackCopy method's catch block within src/social-share-button.js. - The failed copy action is now completely silent internally (since old browsers gracefully failing to copy isn't an unexpected app error), but still visually updates the UI button text to --- src/social-share-button.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/social-share-button.js b/src/social-share-button.js index bfb0de5..27b8ca1 100644 --- a/src/social-share-button.js +++ b/src/social-share-button.js @@ -495,8 +495,7 @@ class SocialShareButton { copyBtn.classList.remove("copied"); this.feedbackTimeout = null; }, 2000); - } catch (error) { - this._debugWarn("Copy to clipboard failed", error); + } catch (_err) { copyBtn.textContent = "Failed"; // Clear any existing feedback timeout From 5c60421f1424a6501052d4a18e3ca7082ba6d9fd Mon Sep 17 00:00:00 2001 From: Aman kumar vishwakrma <186990161+amankv1234@users.noreply.github.com> Date: Sun, 5 Apr 2026 13:42:21 +0530 Subject: [PATCH 10/18] feat: add Nuxt.js integration wrapper and demo documentation --- README.md | 14 ++--- index.html | 92 +++++++++++++++++++++----------- src/social-share-button-nuxt.vue | 80 +++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 38 deletions(-) create mode 100644 src/social-share-button-nuxt.vue diff --git a/README.md b/README.md index 1c21ae4..4ba4b2a 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Lightweight social sharing component for web applications. Zero dependencies, fr - 🌐 Multiple platforms: WhatsApp, Facebook, X, LinkedIn, Telegram, Reddit, Email, Pinterest - 🎯 Zero dependencies - pure vanilla JavaScript -- ⚛️ Framework support: React, Preact, Next.js, Qwik, Vue, Angular, WordPress or plain HTML +- ⚛️ Framework support: React, Preact, Next.js, Nuxt.js, Qwik, Vue, Angular, WordPress or plain HTML - 🔄 Auto-detects current URL and page title - 📱 Fully responsive and mobile-ready - 🎨 Customizable themes (dark/light) @@ -103,11 +103,11 @@ Lightweight social sharing component for web applications. Zero dependencies, fr No matter which framework you use, integration always follows the same 3 steps: -| Step | What to do | Where | -| -------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | -| **1️⃣ Load Library** | Add CSS + JS (CDN links) | Global layout file — `index.html` / `layout.tsx` / `_document.tsx` / `functions.php` | -| **2️⃣ Add Container** | Place `
` | The UI component or WordPress `wp_footer` hook | -| **3️⃣ Initialize** | Call `new SocialShareButton({ container: "#share-button" })` | Inside that component or WordPress `wp_footer` hook | +| Step | What to do | Where | +| -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------ | +| **1️⃣ Load Library** | Add CSS + JS (CDN links) | Global layout file — `index.html` / `layout.tsx` / `_document.tsx` / `functions.php` | +| **2️⃣ Add Container** | Place `
` | The UI component or WordPress `wp_footer` hook | +| **3️⃣ Initialize** | Call `new SocialShareButton({ container: "#share-button" })` | Inside that component or WordPress `wp_footer` hook | > 💡 Pick your framework below for the full copy-paste snippet: @@ -514,7 +514,7 @@ add_action('wp_enqueue_scripts', 'enqueue_social_share_button'); ### Step 2: Initialize in `functions.php` (Footer Hook) -Use the `wp_footer` hook with a **priority of 21** to inject the container and initialization script. The priority must be higher than the default (10) so WordPress prints the enqueued footer scripts *before* this function runs: +Use the `wp_footer` hook with a **priority of 21** to inject the container and initialization script. The priority must be higher than the default (10) so WordPress prints the enqueued footer scripts _before_ this function runs: ```php function init_social_share_button() { ?> diff --git a/index.html b/index.html index 79e8ea5..4bfd381 100644 --- a/index.html +++ b/index.html @@ -491,20 +491,13 @@

🔷 WordPress Integration

style="position: absolute; left: -9999px" > -function enqueue_social_share_button() { - wp_enqueue_style( - 'social-share-button', - 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.css' - ); - wp_enqueue_script( - 'social-share-button', - 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.js', - [], - null, - true // Load in footer - ); -} -add_action('wp_enqueue_scripts', 'enqueue_social_share_button'); + function enqueue_social_share_button() { wp_enqueue_style( 'social-share-button', + 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.css' + ); wp_enqueue_script( 'social-share-button', + 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.js', + [], null, true // Load in footer ); } add_action('wp_enqueue_scripts', + 'enqueue_social_share_button');

Step 2: Initialize the button in the footer

@@ -516,19 +509,12 @@

🔷 WordPress Integration

style="position: absolute; left: -9999px" > -function init_social_share_button() { ?> - <div id="share-button"></div> - <script> - new SocialShareButton({ - container: '#share-button', - url: window.location.href, - title: document.title, - theme: 'dark', - buttonText: 'Share' - }); - </script> -<?php } -add_action('wp_footer', 'init_social_share_button', 21); + function init_social_share_button() { ?> <div id="share-button"></div> + <script> new SocialShareButton({ container: '#share-button', url: + window.location.href, title: document.title, theme: 'dark', buttonText: 'Share' }); + </script> <?php } add_action('wp_footer', 'init_social_share_button', + 21);
@@ -580,6 +566,48 @@

⚡ Qwik / QwikCity Integration

+ +
+

💚 Nuxt.js Integration

+

Step 1: Include CSS and JS via CDN

+ +
+ + + + <link rel="stylesheet" + href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.css"> + <script + src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.js"></script> + +
+ +

+ Step 2: Register the component (auto-imported in Nuxt 3 if placed in + components/) +

+ +

Step 3: Show usage in a pages/index.vue file

+
+ + + + <!-- pages/index.vue --> <template> <SocialShareButton + url="https://your-website.com" title="Check this out!" description="An amazing website" + theme="dark" button-text="Share" /> </template> <script setup> // + Component is auto-imported from components/ in Nuxt 3 </script> + +
+
+

▲ Next.js Integration

Use the component inside a Next.js page

@@ -617,8 +645,6 @@

🅰️ Angular Integration

>
- -