@todovue/tv-toc 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Cristhian Daza
3
+ Copyright (c) 2026 Cristhian Daza
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -5,7 +5,6 @@
5
5
  A lightweight Vue 3 component to render a Table of Contents (TOC) for your articles or documentation, with smooth scrolling and nested sections support.
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/@todovue/tv-toc.svg)](https://www.npmjs.com/package/@todovue/tv-toc)
8
- [![Netlify Status](https://api.netlify.com/api/v1/badges/2a6f2c38-c236-44bb-8d8e-66a86f4295ee/deploy-status)](https://app.netlify.com/projects/tv-toc/deploys)
9
8
  [![npm downloads](https://img.shields.io/npm/dm/@todovue/tv-toc.svg)](https://www.npmjs.com/package/@todovue/tv-toc)
10
9
  [![npm total downloads](https://img.shields.io/npm/dt/@todovue/tv-toc.svg)](https://www.npmjs.com/package/@todovue/tv-toc)
11
10
  ![License](https://img.shields.io/github/license/TODOvue/tv-toc)
@@ -15,7 +14,7 @@ A lightweight Vue 3 component to render a Table of Contents (TOC) for your artic
15
14
  ![Last Commit](https://img.shields.io/github/last-commit/TODOvue/tv-toc)
16
15
  ![Stars](https://img.shields.io/github/stars/TODOvue/tv-toc?style=social)
17
16
 
18
- > Demo: https://tv-toc.netlify.app/
17
+ > Demo: https://ui.todovue.blog/toc
19
18
 
20
19
  ---
21
20
  ## Table of Contents
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),i=()=>({formatId:t=>`#${t}`,scrollToId:t=>{const l=document.getElementById(t);l&&(l.scrollIntoView({behavior:"smooth"}),history.pushState(null,null,`#${t}`))}}),a={class:"tv-toc"},d={key:0,class:"tv-toc-title"},u={class:"tv-toc-list"},m=["href","onClick"],v={key:0,class:"tv-toc-sublist"},h=["href","onClick"],k={__name:"TvToc",props:{toc:{type:Object,required:!0}},setup(o){const{scrollToId:s}=i(),t=l=>{s(l)};return(l,_)=>(e.openBlock(),e.createElementBlock("nav",a,[o.toc?.title?(e.openBlock(),e.createElementBlock("h3",d,e.toDisplayString(o.toc.title),1)):e.createCommentVNode("",!0),e.createElementVNode("ul",u,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.toc?.links,c=>(e.openBlock(),e.createElementBlock("li",{key:c.id,class:"tv-toc-item"},[e.createElementVNode("a",{href:`#${c.id}`,class:"tv-toc-link",onClick:e.withModifiers(n=>t(c.id),["prevent"])},e.toDisplayString(c.text),9,m),c.children?(e.openBlock(),e.createElementBlock("ul",v,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(c.children,n=>(e.openBlock(),e.createElementBlock("li",{key:n.id,class:"tv-toc-subitem"},[e.createElementVNode("a",{href:`#${n.id}`,class:"tv-toc-sublink",onClick:e.withModifiers(p=>t(n.id),["prevent"])},e.toDisplayString(n.text),9,h)]))),128))])):e.createCommentVNode("",!0)]))),128))])]))}},r=k;r.install=o=>{o.component("TvToc",r)};const T={install:r.install};exports.TvToc=r;exports.TvTocPlugin=T;exports.default=r;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),g=(r=[])=>{const a=e.ref(null),d=e.ref(null);let s=null;const u=c=>`#${c}`,v=c=>{const t=document.getElementById(c);t&&(t.scrollIntoView({behavior:"smooth"}),history.pushState(null,null,`#${c}`))},h=c=>{const t=[];return c.forEach(n=>{t.push({id:n.id,parentId:null}),n.children&&n.children.forEach(o=>{t.push({id:o.id,parentId:n.id})})}),t};return{formatId:u,scrollToId:v,activeId:a,activeParentId:d,setupObserver:()=>{if(typeof window>"u"||!r.length)return;const c=h(r),t=c.map(({id:n})=>document.getElementById(n)).filter(n=>n!==null);t.length&&(s=new IntersectionObserver(n=>{n.forEach(o=>{if(o.isIntersecting){const l=o.target.id,f=c.find(I=>I.id===l);f&&(a.value=l,d.value=f.parentId,history.replaceState(null,null,`#${l}`))}})},{rootMargin:"-20% 0px -70% 0px",threshold:0}),t.forEach(n=>s.observe(n)))},cleanup:()=>{s&&(s.disconnect(),s=null)}}},B={class:"tv-toc"},E={key:0,class:"tv-toc-title"},T={class:"tv-toc-list"},_=["href","onClick"],k={key:0,class:"tv-toc-sublist"},y=["href","onClick"],b={__name:"TvToc",props:{toc:{type:Object,required:!0}},setup(r){const a=r,{scrollToId:d,activeId:s,activeParentId:u,setupObserver:v,cleanup:h}=g(a.toc?.links||[]),m=t=>{d(t)},p=t=>s.value===t,c=t=>u.value===t;return e.onMounted(()=>{v()}),e.onUnmounted(()=>{h()}),(t,n)=>(e.openBlock(),e.createElementBlock("nav",B,[r.toc?.title?(e.openBlock(),e.createElementBlock("h3",E,e.toDisplayString(r.toc.title),1)):e.createCommentVNode("",!0),e.createElementVNode("ul",T,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(r.toc?.links,o=>(e.openBlock(),e.createElementBlock("li",{key:o.id,class:"tv-toc-item"},[e.createElementVNode("a",{href:`#${o.id}`,class:e.normalizeClass(["tv-toc-link",{active:p(o.id),"parent-active":c(o.id)}]),onClick:e.withModifiers(l=>m(o.id),["prevent"])},e.toDisplayString(o.text),11,_),o.children?(e.openBlock(),e.createElementBlock("ul",k,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.children,l=>(e.openBlock(),e.createElementBlock("li",{key:l.id,class:"tv-toc-subitem"},[e.createElementVNode("a",{href:`#${l.id}`,class:e.normalizeClass(["tv-toc-sublink",{active:p(l.id)}]),onClick:e.withModifiers(f=>m(l.id),["prevent"])},e.toDisplayString(l.text),11,y)]))),128))])):e.createCommentVNode("",!0)]))),128))])]))}},i=b;i.install=r=>{r.component("TvToc",i)};const C={install:i.install};exports.TvToc=i;exports.TvTocPlugin=C;exports.default=i;
package/dist/tv-toc.css CHANGED
@@ -1 +1 @@
1
- .tv-toc{padding:1rem;background-color:#b9c4df;border-radius:8px;color:#000b14;min-width:200px}@media(prefers-color-scheme:dark){.tv-toc{background-color:#0e131f;color:#f4faff}}.tv-toc .tv-toc-title{font-size:1.2rem;font-weight:700;margin-bottom:.5rem}.tv-toc .tv-toc-list{list-style:none;padding:0;margin:0}.tv-toc .tv-toc-item{margin-bottom:.5rem}.tv-toc .tv-toc-link{text-decoration:none;color:inherit;font-weight:500;transition:color .2s}.tv-toc .tv-toc-link:hover{color:#ef233c}@media(prefers-color-scheme:dark){.tv-toc .tv-toc-link:hover{color:#ef233c}}.tv-toc .tv-toc-sublist{list-style:none;padding-left:1rem;margin-top:.25rem;border-left:2px solid rgba(0,11,20,.1)}@media(prefers-color-scheme:dark){.tv-toc .tv-toc-sublist{border-left-color:#f4faff1a}}.tv-toc .tv-toc-subitem{margin-bottom:.25rem}.tv-toc .tv-toc-sublink{text-decoration:none;color:inherit;font-size:.9rem;opacity:.8;transition:opacity .2s,color .2s}.tv-toc .tv-toc-sublink:hover{opacity:1;color:#ef233c}@media(prefers-color-scheme:dark){.tv-toc .tv-toc-sublink:hover{color:#ef233c}}.light-mode .tv-toc{background-color:#b9c4df;color:#000b14}.light-mode .tv-toc .tv-toc-link:hover{color:#ef233c}.light-mode .tv-toc .tv-toc-sublist{border-left-color:#000b141a}.light-mode .tv-toc .tv-toc-sublink:hover{color:#ef233c}
1
+ .tv-toc{padding:1rem;background-color:#b9c4df;border-radius:8px;color:#000b14;min-width:200px}@media(prefers-color-scheme:dark){.tv-toc{background-color:#0e131f;color:#f4faff}}.tv-toc .tv-toc-title{font-size:1.2rem;font-weight:700;margin-bottom:.5rem}.tv-toc .tv-toc-list{list-style:none;padding:0;margin:0}.tv-toc .tv-toc-item{margin-bottom:.5rem;position:relative}.tv-toc .tv-toc-item:hover .tv-toc-link,.tv-toc .tv-toc-item:hover .tv-toc-sublink{background-color:#ef233c0d}@media(prefers-color-scheme:dark){.tv-toc .tv-toc-item:hover .tv-toc-link,.tv-toc .tv-toc-item:hover .tv-toc-sublink{background-color:#ef233c0d}}.tv-toc .tv-toc-link{display:block;text-decoration:none;color:inherit;font-weight:500;padding:.5rem .75rem;border-radius:4px;transition:all .3s ease;position:relative}.tv-toc .tv-toc-link:hover{color:#ef233c}.tv-toc .tv-toc-link.active{color:#ef233c;font-weight:700;background-color:#ef233c1a;border-left:3px solid #EF233C;padding-left:calc(1rem - 3px)}.tv-toc .tv-toc-link.parent-active{color:#ef233c;font-weight:500;border-left:2px solid rgba(239,35,60,.5);padding-left:calc(1rem - 2px)}@media(prefers-color-scheme:dark){.tv-toc .tv-toc-link:hover{color:#ef233c}.tv-toc .tv-toc-link.active{color:#ef233c;background-color:#ef233c1a;border-left-color:#ef233c}.tv-toc .tv-toc-link.parent-active{color:#ef233c;border-left-color:#ef233c80}}.tv-toc .tv-toc-sublist{list-style:none;padding-left:1rem;margin-top:.25rem;margin-bottom:.25rem;border-left:2px solid rgba(0,11,20,.1)}@media(prefers-color-scheme:dark){.tv-toc .tv-toc-sublist{border-left-color:#f4faff1a}}.tv-toc .tv-toc-subitem{margin-bottom:.25rem;position:relative}.tv-toc .tv-toc-sublink{display:block;text-decoration:none;color:inherit;font-size:.9rem;opacity:.8;padding:.4rem .75rem;border-radius:4px;transition:all .3s ease;position:relative}.tv-toc .tv-toc-sublink:hover{opacity:1;color:#ef233c}.tv-toc .tv-toc-sublink.active{opacity:1;color:#ef233c;font-weight:700;background-color:#ef233c1a;border-left:3px solid #EF233C;padding-left:calc(1rem - 3px)}@media(prefers-color-scheme:dark){.tv-toc .tv-toc-sublink:hover{color:#ef233c}.tv-toc .tv-toc-sublink.active{color:#ef233c;background-color:#ef233c1a;border-left-color:#ef233c}}.light-mode .tv-toc{background-color:#b9c4df;color:#000b14}.light-mode .tv-toc .tv-toc-link:hover{color:#ef233c}.light-mode .tv-toc .tv-toc-link.active,.light-mode .tv-toc .tv-toc-link.parent-active{color:#ef233c;border-left-color:#ef233c}.light-mode .tv-toc .tv-toc-link.parent-active{border-left-color:#ef233c80}.light-mode .tv-toc .tv-toc-sublist{border-left-color:#000b141a}.light-mode .tv-toc .tv-toc-sublink:hover,.light-mode .tv-toc .tv-toc-sublink.active{color:#ef233c}.light-mode .tv-toc .tv-toc-sublink.active{border-left-color:#ef233c}
package/dist/tv-toc.es.js CHANGED
@@ -1,17 +1,52 @@
1
- import { createElementBlock as e, openBlock as o, createCommentVNode as u, createElementVNode as r, toDisplayString as i, Fragment as h, renderList as m, withModifiers as v } from "vue";
2
- const _ = () => ({
3
- formatId: (t) => `#${t}`,
4
- scrollToId: (t) => {
5
- const l = document.getElementById(t);
6
- l && (l.scrollIntoView({ behavior: "smooth" }), history.pushState(null, null, `#${t}`));
7
- }
8
- }), T = { class: "tv-toc" }, f = {
1
+ import { ref as T, onMounted as O, onUnmounted as w, createElementBlock as r, openBlock as i, createCommentVNode as y, createElementVNode as I, toDisplayString as _, Fragment as E, renderList as b, withModifiers as C, normalizeClass as $ } from "vue";
2
+ const B = (s = []) => {
3
+ const a = T(null), d = T(null);
4
+ let l = null;
5
+ const u = (o) => `#${o}`, v = (o) => {
6
+ const t = document.getElementById(o);
7
+ t && (t.scrollIntoView({ behavior: "smooth" }), history.pushState(null, null, `#${o}`));
8
+ }, h = (o) => {
9
+ const t = [];
10
+ return o.forEach((e) => {
11
+ t.push({ id: e.id, parentId: null }), e.children && e.children.forEach((n) => {
12
+ t.push({ id: n.id, parentId: e.id });
13
+ });
14
+ }), t;
15
+ };
16
+ return {
17
+ formatId: u,
18
+ scrollToId: v,
19
+ activeId: a,
20
+ activeParentId: d,
21
+ setupObserver: () => {
22
+ if (typeof window > "u" || !s.length) return;
23
+ const o = h(s), t = o.map(({ id: e }) => document.getElementById(e)).filter((e) => e !== null);
24
+ t.length && (l = new IntersectionObserver(
25
+ (e) => {
26
+ e.forEach((n) => {
27
+ if (n.isIntersecting) {
28
+ const c = n.target.id, m = o.find((x) => x.id === c);
29
+ m && (a.value = c, d.value = m.parentId, history.replaceState(null, null, `#${c}`));
30
+ }
31
+ });
32
+ },
33
+ {
34
+ rootMargin: "-20% 0px -70% 0px",
35
+ threshold: 0
36
+ }
37
+ ), t.forEach((e) => l.observe(e)));
38
+ },
39
+ cleanup: () => {
40
+ l && (l.disconnect(), l = null);
41
+ }
42
+ };
43
+ }, P = { class: "tv-toc" }, A = {
9
44
  key: 0,
10
45
  class: "tv-toc-title"
11
- }, p = { class: "tv-toc-list" }, y = ["href", "onClick"], I = {
46
+ }, M = { class: "tv-toc-list" }, S = ["href", "onClick"], V = {
12
47
  key: 0,
13
48
  class: "tv-toc-sublist"
14
- }, k = ["href", "onClick"], C = {
49
+ }, N = ["href", "onClick"], j = {
15
50
  __name: "TvToc",
16
51
  props: {
17
52
  toc: {
@@ -19,47 +54,54 @@ const _ = () => ({
19
54
  required: !0
20
55
  }
21
56
  },
22
- setup(c) {
23
- const { scrollToId: d } = _(), t = (l) => {
24
- d(l);
25
- };
26
- return (l, $) => (o(), e("nav", T, [
27
- c.toc?.title ? (o(), e("h3", f, i(c.toc.title), 1)) : u("", !0),
28
- r("ul", p, [
29
- (o(!0), e(h, null, m(c.toc?.links, (s) => (o(), e("li", {
30
- key: s.id,
57
+ setup(s) {
58
+ const a = s, { scrollToId: d, activeId: l, activeParentId: u, setupObserver: v, cleanup: h } = B(a.toc?.links || []), f = (t) => {
59
+ d(t);
60
+ }, p = (t) => l.value === t, o = (t) => u.value === t;
61
+ return O(() => {
62
+ v();
63
+ }), w(() => {
64
+ h();
65
+ }), (t, e) => (i(), r("nav", P, [
66
+ s.toc?.title ? (i(), r("h3", A, _(s.toc.title), 1)) : y("", !0),
67
+ I("ul", M, [
68
+ (i(!0), r(E, null, b(s.toc?.links, (n) => (i(), r("li", {
69
+ key: n.id,
31
70
  class: "tv-toc-item"
32
71
  }, [
33
- r("a", {
34
- href: `#${s.id}`,
35
- class: "tv-toc-link",
36
- onClick: v((n) => t(s.id), ["prevent"])
37
- }, i(s.text), 9, y),
38
- s.children ? (o(), e("ul", I, [
39
- (o(!0), e(h, null, m(s.children, (n) => (o(), e("li", {
40
- key: n.id,
72
+ I("a", {
73
+ href: `#${n.id}`,
74
+ class: $(["tv-toc-link", {
75
+ active: p(n.id),
76
+ "parent-active": o(n.id)
77
+ }]),
78
+ onClick: C((c) => f(n.id), ["prevent"])
79
+ }, _(n.text), 11, S),
80
+ n.children ? (i(), r("ul", V, [
81
+ (i(!0), r(E, null, b(n.children, (c) => (i(), r("li", {
82
+ key: c.id,
41
83
  class: "tv-toc-subitem"
42
84
  }, [
43
- r("a", {
44
- href: `#${n.id}`,
45
- class: "tv-toc-sublink",
46
- onClick: v((g) => t(n.id), ["prevent"])
47
- }, i(n.text), 9, k)
85
+ I("a", {
86
+ href: `#${c.id}`,
87
+ class: $(["tv-toc-sublink", { active: p(c.id) }]),
88
+ onClick: C((m) => f(c.id), ["prevent"])
89
+ }, _(c.text), 11, N)
48
90
  ]))), 128))
49
- ])) : u("", !0)
91
+ ])) : y("", !0)
50
92
  ]))), 128))
51
93
  ])
52
94
  ]));
53
95
  }
54
- }, a = C;
55
- a.install = (c) => {
56
- c.component("TvToc", a);
96
+ }, g = j;
97
+ g.install = (s) => {
98
+ s.component("TvToc", g);
57
99
  };
58
- const B = {
59
- install: a.install
100
+ const q = {
101
+ install: g.install
60
102
  };
61
103
  export {
62
- a as TvToc,
63
- B as TvTocPlugin,
64
- a as default
104
+ g as TvToc,
105
+ q as TvTocPlugin,
106
+ g as default
65
107
  };
package/package.json CHANGED
@@ -4,11 +4,12 @@
4
4
  "author": "Cristhian Daza",
5
5
  "description": "A Vue 3 component to generate a table of contents (TOC) for your articles or documentation, enhancing navigation and user experience.",
6
6
  "license": "MIT",
7
- "version": "1.0.1",
7
+ "version": "1.0.2",
8
8
  "type": "module",
9
+ "homepage": "https://ui.todovue.blog/toc",
9
10
  "repository": {
10
11
  "type": "git",
11
- "url": "https://github.com/TODOvue/tv-toc.git"
12
+ "url": "git+https://github.com/TODOvue/tv-toc.git"
12
13
  },
13
14
  "bugs": {
14
15
  "url": "https://github.com/TODOvue/tv-toc/issues"
@@ -56,13 +57,13 @@
56
57
  "build:demo": "cp README.md public/ && cp CHANGELOG.md public/ && VITE_BUILD_TARGET=demo vite build"
57
58
  },
58
59
  "peerDependencies": {
59
- "vue": "^3.0.0"
60
+ "vue": "^3.5.26"
60
61
  },
61
62
  "devDependencies": {
62
- "@todovue/tv-demo": "^1.2.2",
63
- "@vitejs/plugin-vue": "^6.0.0",
64
- "sass": "^1.0.0",
65
- "vite": "^7.0.0",
66
- "vite-plugin-dts": "^4.0.0"
63
+ "@todovue/tv-demo": "^1.2.7",
64
+ "@vitejs/plugin-vue": "^6.0.3",
65
+ "sass": "^1.97.1",
66
+ "vite": "^7.3.0",
67
+ "vite-plugin-dts": "^4.5.4"
67
68
  }
68
69
  }