[{"data":1,"prerenderedAt":1066},["ShallowReactive",2],{"snippets":3,"categories":1047},[4,20,32,42,52,61,70,79,88,97,106,117,127,135,143,152,161,169,177,185,194,202,211,220,229,237,245,254,261,269,278,290,302,313,324,335,344,354,364,372,383,394,404,414,423,433,441,450,460,469,478,489,497,505,513,520,528,536,544,551,558,565,573,581,589,596,605,615,622,630,638,646,654,662,670,677,684,692,701,708,716,723,730,738,746,754,761,770,777,785,793,800,808,815,823,830,837,845,854,860,867,873,879,885,892,899,905,913,920,926,932,939,947,953,959,965,972,979,986,993,1000,1006,1013,1022,1028,1035,1041],{"id":5,"category":6,"title":7,"description":8,"author":9,"date":10,"tags":11,"code":16,"html":17,"previewBg":18,"canPreview":19},"css-glassmorphism-card","css","Glassmorphism Card","Modern glass-effect card component using backdrop-filter for stunning UI design","Ovvth","2024-12-12",[12,13,14,15],"CSS3","Glassmorphism","Card","UI",".glass-card {\n  background: rgba(255, 255, 255, 0.1);\n  backdrop-filter: blur(10px);\n  -webkit-backdrop-filter: blur(10px);\n  border-radius: 16px;\n  border: 1px solid rgba(255, 255, 255, 0.2);\n  padding: 24px;\n  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);\n}","\u003Cdiv class=\"glass-card\">\n  \u003Ch3>Glass Card\u003C/h3>\n  \u003Cp>A beautiful glassmorphism card using CSS backdrop-filter.\u003C/p>\n\u003C/div>","linear-gradient(135deg, #667eea 0%, #764ba2 100%)",true,{"id":21,"category":6,"title":22,"description":23,"author":9,"date":10,"tags":24,"code":29,"html":30,"previewBg":31,"canPreview":19},"css-neon-button","Neon Glow Button","Eye-catching neon glow button with hover animation effects",[12,25,26,27,28],"Neon","Button","Animation","Hover",".neon-button {\n  padding: 12px 32px;\n  font-size: 18px;\n  border: none;\n  border-radius: 8px;\n  background: #000;\n  color: #fff;\n  cursor: pointer;\n  box-shadow: 0 0 5px #0ff, 0 0 20px #0ff;\n  transition: all 0.3s ease;\n}\n.neon-button:hover {\n  box-shadow: 0 0 10px #0ff, 0 0 30px #0ff, 0 0 60px #0ff;\n  transform: translateY(-2px);\n}","\u003Cbutton class=\"neon-button\">Neon Button\u003C/button>","#000",{"id":33,"category":6,"title":34,"description":35,"author":9,"date":10,"tags":36,"code":40,"html":41,"previewBg":18,"canPreview":19},"css-3d-text","3D Text Effect","Stunning 3D text with layered shadows and perspective",[12,37,38,39],"3D","Text","Perspective",".text-3d {\n  font-size: 72px;\n  font-weight: 900;\n  color: #4158d0;\n  text-transform: uppercase;\n  text-shadow: 0 1px 0 #ccc,\n               0 2px 0 #c9c9c9,\n               0 3px 0 #bbb,\n               0 4px 0 #b9b9b9,\n               0 5px 0 #aaa,\n               0 6px 1px rgba(0,0,0,.1),\n               0 0 5px rgba(0,0,0,.1),\n               0 1px 3px rgba(0,0,0,.3),\n               0 3px 5px rgba(0,0,0,.2),\n               0 5px 10px rgba(0,0,0,.25),\n               0 10px 10px rgba(0,0,0,.2),\n               0 20px 20px rgba(0,0,0,.15);\n  transform: perspective(500px) rotateX(15deg);\n}","\u003Ch1 class=\"text-3d\">3D Text\u003C/h1>",{"id":43,"category":6,"title":44,"description":45,"author":9,"date":10,"tags":46,"code":50,"html":51,"previewBg":18,"canPreview":19},"css-gradient-border","Gradient Border Card","Card with beautiful gradient border using CSS pseudo-elements",[12,47,48,14,49],"Gradient","Border","Pseudo-elements",".gradient-border-card {\n  position: relative;\n  width: 300px;\n  height: 200px;\n  padding: 24px;\n  border-radius: 16px;\n  background: #fff;\n  overflow: hidden;\n}\n.gradient-border-card::before {\n  content: '';\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  border: 2px solid transparent;\n  border-radius: 16px;\n  background: linear-gradient(45deg, #ff6b6b, #4ecdc4) border-box;\n  -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);\n  -webkit-mask-composite: xor;\n  mask-composite: exclude;\n  pointer-events: none;\n}","\u003Cdiv class=\"gradient-border-card\">\n  \u003Ch3>Gradient Border\u003C/h3>\n  \u003Cp>Card with gradient border effect\u003C/p>\n\u003C/div>",{"id":53,"category":6,"title":54,"description":55,"author":9,"date":10,"tags":56,"code":59,"html":60,"previewBg":18,"canPreview":19},"css-pulse-animation","Pulse Animation Effect","Smooth pulse animation for UI elements like notifications or buttons",[12,27,57,58],"Pulse","Keyframes",".pulse-effect {\n  width: 60px;\n  height: 60px;\n  border-radius: 50%;\n  background: #ff2e63;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: white;\n  font-weight: bold;\n  position: relative;\n}\n.pulse-effect::before {\n  content: '';\n  position: absolute;\n  top: -10px;\n  left: -10px;\n  right: -10px;\n  bottom: -10px;\n  border-radius: 50%;\n  background: #ff2e63;\n  opacity: 0.4;\n  animation: pulse 2s infinite;\n}\n@keyframes pulse {\n  0% {\n    transform: scale(0.8);\n    opacity: 0.7;\n  }\n  50% {\n    transform: scale(1.2);\n    opacity: 0;\n  }\n  100% {\n    transform: scale(0.8);\n    opacity: 0.7;\n  }\n}","\u003Cdiv class=\"pulse-effect\">99+\u003C/div>",{"id":62,"category":6,"title":63,"description":64,"author":9,"date":10,"tags":65,"code":68,"html":69,"previewBg":18,"canPreview":19},"css-fluid-animation","Fluid Wave Animation","Smooth fluid wave animation using CSS keyframes and transforms",[12,27,66,67,58],"Fluid","Wave",".fluid-wave {\n  width: 300px;\n  height: 150px;\n  position: relative;\n  overflow: hidden;\n  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n  border-radius: 16px;\n}\n.fluid-wave::before {\n  content: '';\n  position: absolute;\n  width: 400px;\n  height: 400px;\n  top: -250px;\n  left: 50%;\n  transform: translateX(-50%);\n  background: rgba(255,255,255,0.1);\n  border-radius: 45%;\n  animation: wave 8s linear infinite;\n}\n.fluid-wave::after {\n  content: '';\n  position: absolute;\n  width: 400px;\n  height: 400px;\n  top: -240px;\n  left: 50%;\n  transform: translateX(-50%);\n  background: rgba(255,255,255,0.05);\n  border-radius: 40%;\n  animation: wave 10s linear infinite;\n}\n@keyframes wave {\n  0% {\n    transform: translateX(-50%) rotate(0deg);\n  }\n  100% {\n    transform: translateX(-50%) rotate(360deg);\n  }\n}","\u003Cdiv class=\"fluid-wave\">\u003C/div>",{"id":71,"category":6,"title":72,"description":73,"author":9,"date":10,"tags":74,"code":77,"html":78,"previewBg":18,"canPreview":19},"css-skew-card","Skew Transform Card","Stylish skew transform card with hover effect and perspective",[12,75,76,14,28],"Transform","Skew",".skew-card {\n  width: 300px;\n  height: 200px;\n  background: linear-gradient(45deg, #ff9a9e 0%, #fad0c4 99%, #fad0c4 100%);\n  border-radius: 8px;\n  transform: skew(-10deg);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  transition: all 0.3s ease;\n  box-shadow: 0 10px 20px rgba(0,0,0,0.1);\n}\n.skew-card:hover {\n  transform: skew(-10deg) scale(1.05);\n  box-shadow: 0 15px 30px rgba(0,0,0,0.2);\n}\n.skew-content {\n  transform: skew(10deg);\n  color: white;\n  font-size: 24px;\n  font-weight: bold;\n}","\u003Cdiv class=\"skew-card\">\n  \u003Cdiv class=\"skew-content\">Skew Card\u003C/div>\n\u003C/div>",{"id":80,"category":6,"title":81,"description":82,"author":9,"date":10,"tags":83,"code":86,"html":87,"previewBg":18,"canPreview":19},"css-grid-hover","Grid Item Hover Effect","Elegant grid item hover effect with scale and shadow transition",[12,84,28,85,14],"Grid","Transition",".grid-container {\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  gap: 20px;\n  padding: 20px;\n}\n.grid-item {\n  height: 200px;\n  border-radius: 12px;\n  background: #fff;\n  box-shadow: 0 4px 6px rgba(0,0,0,0.1);\n  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n  overflow: hidden;\n  position: relative;\n}\n.grid-item::before {\n  content: '';\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: linear-gradient(45deg, #84fab0 0%, #8fd3f4 100%);\n  opacity: 0;\n  transition: opacity 0.3s ease;\n}\n.grid-item:hover {\n  transform: translateY(-8px) scale(1.02);\n  box-shadow: 0 20px 25px rgba(0,0,0,0.15);\n}\n.grid-item:hover::before {\n  opacity: 0.8;\n}","\u003Cdiv class=\"grid-container\">\n  \u003Cdiv class=\"grid-item\">\u003C/div>\n  \u003Cdiv class=\"grid-item\">\u003C/div>\n  \u003Cdiv class=\"grid-item\">\u003C/div>\n\u003C/div>",{"id":89,"category":6,"title":90,"description":91,"author":9,"date":10,"tags":92,"code":95,"html":96,"previewBg":18,"canPreview":19},"css-loading-spinner","Animated Loading Spinner","Smooth rotating loading spinner with gradient border",[12,27,93,94,58],"Loading","Spinner",".spinner {\n  width: 50px;\n  height: 50px;\n  border: 5px solid rgba(102, 126, 234, 0.2);\n  border-radius: 50%;\n  border-top-color: #667eea;\n  animation: spin 1s ease-in-out infinite;\n}\n@keyframes spin {\n  to {\n    transform: rotate(360deg);\n  }\n}","\u003Cdiv class=\"spinner\">\u003C/div>",{"id":98,"category":6,"title":99,"description":100,"author":9,"date":10,"tags":101,"code":103,"html":104,"previewBg":105,"canPreview":19},"css-text-gradient","Gradient Text Effect","Vibrant gradient text with background clip and text fill",[12,47,38,102],"Background-clip",".text-gradient {\n  font-size: 48px;\n  font-weight: 800;\n  background: linear-gradient(90deg, #ff8a00, #e52e71);\n  -webkit-background-clip: text;\n  background-clip: text;\n  -webkit-text-fill-color: transparent;\n  text-fill-color: transparent;\n}","\u003Ch2 class=\"text-gradient\">Gradient Text\u003C/h2>","#fff",{"id":107,"category":6,"title":108,"description":109,"author":9,"date":10,"tags":110,"code":115,"html":116,"previewBg":18,"canPreview":19},"css-scroll-indicator","Scroll Progress Indicator","Dynamic scroll progress bar at the top of the page",[12,111,112,113,114],"Scroll","Progress","JavaScript","Indicator","/* Add JS: window.onscroll = function() {myFunction()}; function myFunction() { var winScroll = document.body.scrollTop || document.documentElement.scrollTop; var height = document.documentElement.scrollHeight - document.documentElement.clientHeight; var scrolled = (winScroll / height) * 100; document.getElementById(\"scrollIndicator\").style.width = scrolled + \"%\"; } */\n.scroll-indicator {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 0;\n  height: 4px;\n  background: linear-gradient(90deg, #43e97b 0%, #38f9d7 100%);\n  z-index: 9999;\n  transition: width 0.1s ease;\n}","\u003Cdiv id=\"scrollIndicator\" class=\"scroll-indicator\">\u003C/div>\n\u003Cdiv style=\"height: 2000px; padding: 20px;\">\n  \u003Ch3>Scroll Down to See Progress\u003C/h3>\n\u003C/div>",{"id":118,"category":6,"title":119,"description":120,"author":9,"date":10,"tags":121,"code":125,"html":126,"previewBg":18,"canPreview":19},"css-toggle-switch","Custom Toggle Switch","Stylish custom toggle switch replacement for checkbox",[12,122,123,124,15],"Toggle","Switch","Checkbox",".toggle-switch {\n  position: relative;\n  display: inline-block;\n  width: 60px;\n  height: 30px;\n}\n.toggle-switch input {\n  opacity: 0;\n  width: 0;\n  height: 0;\n}\n.toggle-slider {\n  position: absolute;\n  cursor: pointer;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  background-color: #ccc;\n  transition: .4s;\n  border-radius: 30px;\n}\n.toggle-slider:before {\n  position: absolute;\n  content: \"\";\n  height: 22px;\n  width: 22px;\n  left: 4px;\n  bottom: 4px;\n  background-color: white;\n  transition: .4s;\n  border-radius: 50%;\n}\ninput:checked + .toggle-slider {\n  background-color: #2196F3;\n}\ninput:checked + .toggle-slider:before {\n  transform: translateX(30px);\n}","\u003Clabel class=\"toggle-switch\">\n  \u003Cinput type=\"checkbox\">\n  \u003Cspan class=\"toggle-slider\">\u003C/span>\n\u003C/label>",{"id":128,"category":6,"title":129,"description":130,"author":9,"date":10,"tags":131,"code":133,"html":134,"previewBg":18,"canPreview":19},"css-parallax-card","Parallax Hover Card","3D parallax effect on card hover with mouse movement tracking",[12,132,28,37,75],"Parallax","/* Add JS: document.querySelector('.parallax-card').addEventListener('mousemove', function(e) { const x = (e.clientX - this.offsetLeft - this.offsetWidth/2) / 20; const y = (e.clientY - this.offsetTop - this.offsetHeight/2) / 20; this.style.transform = `rotateY(${x}deg) rotateX(${-y}deg)`; }); document.querySelector('.parallax-card').addEventListener('mouseleave', function() { this.style.transform = 'rotateY(0) rotateX(0)'; }); */\n.parallax-card {\n  width: 300px;\n  height: 400px;\n  background: #fff;\n  border-radius: 20px;\n  box-shadow: 0 20px 40px rgba(0,0,0,0.1);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  transition: transform 0.2s ease-out;\n  transform-style: preserve-3d;\n  perspective: 1000px;\n}\n.parallax-content {\n  font-size: 24px;\n  font-weight: bold;\n  color: #333;\n  transform: translateZ(20px);\n}","\u003Cdiv class=\"parallax-card\">\n  \u003Cdiv class=\"parallax-content\">Parallax Card\u003C/div>\n\u003C/div>",{"id":136,"category":6,"title":137,"description":138,"author":9,"date":10,"tags":139,"code":141,"html":142,"previewBg":18,"canPreview":19},"css-bounce-animation","Bounce Animation Effect","Playful bounce animation for UI elements on interaction",[12,27,140,58,28],"Bounce",".bounce-effect {\n  width: 80px;\n  height: 80px;\n  border-radius: 50%;\n  background: linear-gradient(45deg, #ff6b6b, #4ecdc4);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: white;\n  font-weight: bold;\n  cursor: pointer;\n}\n.bounce-effect:hover {\n  animation: bounce 0.6s ease;\n}\n@keyframes bounce {\n  0%, 20%, 50%, 80%, 100% {\n    transform: translateY(0);\n  }\n  40% {\n    transform: translateY(-20px);\n  }\n  60% {\n    transform: translateY(-10px);\n  }\n}","\u003Cdiv class=\"bounce-effect\">Bounce\u003C/div>",{"id":144,"category":6,"title":145,"description":146,"author":9,"date":10,"tags":147,"code":150,"html":151,"previewBg":18,"canPreview":19},"css-blur-hover","Blur Hover Effect","Smooth blur to clear transition on card hover",[12,148,28,149,85],"Blur","Filter",".blur-card {\n  width: 300px;\n  height: 200px;\n  background: #fff;\n  border-radius: 12px;\n  padding: 24px;\n  box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n  filter: blur(4px);\n  transition: all 0.4s ease;\n  opacity: 0.8;\n}\n.blur-card:hover {\n  filter: blur(0);\n  opacity: 1;\n  transform: scale(1.03);\n  box-shadow: 0 8px 24px rgba(0,0,0,0.15);\n}","\u003Cdiv class=\"blur-card\">\n  \u003Ch3>Blur Hover\u003C/h3>\n  \u003Cp>Hover to remove blur effect\u003C/p>\n\u003C/div>",{"id":153,"category":6,"title":154,"description":155,"author":9,"date":10,"tags":156,"code":159,"html":160,"previewBg":18,"canPreview":19},"css-ribbon","CSS Ribbon Badge","Stylish ribbon badge with angled corners and shadow effect",[12,157,158,49],"Ribbon","Badge",".ribbon {\n  position: relative;\n  background: #ff4757;\n  color: white;\n  font-weight: bold;\n  padding: 8px 24px 8px 16px;\n  display: inline-block;\n  margin: 20px;\n}\n.ribbon::after {\n  content: '';\n  position: absolute;\n  right: 0;\n  bottom: -10px;\n  border-width: 10px 10px 0 0;\n  border-style: solid;\n  border-color: #d63031 transparent;\n}\n.ribbon::before {\n  content: '';\n  position: absolute;\n  top: 100%;\n  left: 0;\n  width: 100%;\n  height: 10px;\n  background: linear-gradient(135deg, transparent 10px, #ff4757 0);\n}","\u003Cdiv class=\"ribbon\">New\u003C/div>",{"id":162,"category":6,"title":163,"description":164,"author":9,"date":10,"tags":165,"code":167,"html":168,"previewBg":105,"canPreview":19},"css-typewriter","Typewriter Animation","Realistic typewriter text animation with cursor blinking",[12,27,166,58,38],"Typewriter",".typewriter {\n  font-size: 24px;\n  font-family: monospace;\n  overflow: hidden;\n  border-right: 2px solid #000;\n  white-space: nowrap;\n  margin: 0 auto;\n  letter-spacing: 0.15em;\n  animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite;\n}\n@keyframes typing {\n  from { width: 0 }\n  to { width: 100% }\n}\n@keyframes blink-caret {\n  from, to { border-color: transparent }\n  50% { border-color: black }\n}","\u003Cp class=\"typewriter\">CSS Typewriter Animation\u003C/p>",{"id":170,"category":6,"title":171,"description":172,"author":9,"date":10,"tags":173,"code":175,"html":176,"previewBg":18,"canPreview":19},"css-rainbow-loader","Rainbow Loading Bar","Colorful rainbow loading bar with smooth animation",[12,27,93,174,112],"Rainbow",".rainbow-loader {\n  height: 8px;\n  width: 100%;\n  max-width: 400px;\n  border-radius: 4px;\n  background: linear-gradient(90deg, #ff0000, #ff9900, #33cc33, #3399ff, #cc33ff);\n  background-size: 400% 100%;\n  animation: rainbow 3s linear infinite;\n}\n@keyframes rainbow {\n  0% {\n    background-position: 0% 50%;\n  }\n  100% {\n    background-position: 100% 50%;\n  }\n}","\u003Cdiv class=\"rainbow-loader\">\u003C/div>",{"id":178,"category":6,"title":179,"description":180,"author":9,"date":10,"tags":181,"code":183,"html":184,"previewBg":18,"canPreview":19},"css-3d-cube","3D Rotating Cube","Animated 3D cube with perspective and transform effects",[12,37,182,75,27],"Cube",".cube-container {\n  width: 200px;\n  height: 200px;\n  perspective: 1000px;\n}\n.cube {\n  width: 100%;\n  height: 100%;\n  position: relative;\n  transform-style: preserve-3d;\n  animation: rotateCube 10s infinite linear;\n}\n.cube-face {\n  position: absolute;\n  width: 200px;\n  height: 200px;\n  border: 2px solid #333;\n  opacity: 0.8;\n}\n.face-front { background: #ff6b6b; transform: translateZ(100px); }\n.face-back { background: #4ecdc4; transform: rotateY(180deg) translateZ(100px); }\n.face-right { background: #ffe66d; transform: rotateY(90deg) translateZ(100px); }\n.face-left { background: #1a535c; transform: rotateY(-90deg) translateZ(100px); }\n.face-top { background: #7209b7; transform: rotateX(90deg) translateZ(100px); }\n.face-bottom { background: #f72585; transform: rotateX(-90deg) translateZ(100px); }\n@keyframes rotateCube {\n  0% { transform: rotateX(0) rotateY(0); }\n  100% { transform: rotateX(360deg) rotateY(360deg); }\n}","\u003Cdiv class=\"cube-container\">\n  \u003Cdiv class=\"cube\">\n    \u003Cdiv class=\"cube-face face-front\">\u003C/div>\n    \u003Cdiv class=\"cube-face face-back\">\u003C/div>\n    \u003Cdiv class=\"cube-face face-right\">\u003C/div>\n    \u003Cdiv class=\"cube-face face-left\">\u003C/div>\n    \u003Cdiv class=\"cube-face face-top\">\u003C/div>\n    \u003Cdiv class=\"cube-face face-bottom\">\u003C/div>\n  \u003C/div>\n\u003C/div>",{"id":186,"category":6,"title":187,"description":188,"author":9,"date":10,"tags":189,"code":192,"html":193,"previewBg":105,"canPreview":19},"css-shimmer-effect","Shimmer Loading Effect","Smooth shimmer effect for skeleton loading screens",[12,190,93,191,27],"Shimmer","Skeleton",".shimmer-container {\n  width: 300px;\n  height: 200px;\n  background: #f6f7f8;\n  background-image: linear-gradient(to right, #f6f7f8 0%, #edeef1 20%, #f6f7f8 40%, #f6f7f8 100%);\n  background-repeat: no-repeat;\n  background-size: 800px 100%;\n  animation: shimmer 1.5s linear infinite;\n  border-radius: 8px;\n}\n@keyframes shimmer {\n  0% {\n    background-position: -400px 0;\n  }\n  100% {\n    background-position: 400px 0;\n  }\n}","\u003Cdiv class=\"shimmer-container\">\u003C/div>",{"id":195,"category":6,"title":196,"description":197,"author":9,"date":10,"tags":198,"code":200,"html":201,"previewBg":18,"canPreview":19},"css-underline-effect","Animated Underline","Elegant animated underline effect on text hover",[12,199,28,27,38],"Underline",".animated-underline {\n  font-size: 24px;\n  font-weight: 600;\n  color: #333;\n  text-decoration: none;\n  position: relative;\n}\n.animated-underline::after {\n  content: '';\n  position: absolute;\n  width: 0;\n  height: 3px;\n  bottom: -4px;\n  left: 0;\n  background: linear-gradient(90deg, #43e97b 0%, #38f9d7 100%);\n  transition: width 0.3s ease;\n}\n.animated-underline:hover::after {\n  width: 100%;\n}","\u003Ca href=\"#\" class=\"animated-underline\">Animated Underline\u003C/a>",{"id":203,"category":6,"title":204,"description":205,"author":9,"date":10,"tags":206,"code":209,"html":210,"previewBg":18,"canPreview":19},"css-bubble-animation","Bubble Animation","Floating bubble animation for background decoration",[12,27,207,58,208],"Bubble","Background",".bubble-container {\n  width: 400px;\n  height: 300px;\n  background: #667eea;\n  border-radius: 16px;\n  position: relative;\n  overflow: hidden;\n}\n.bubble {\n  position: absolute;\n  border-radius: 50%;\n  background: rgba(255,255,255,0.2);\n  animation: float 8s infinite ease-in-out;\n}\n.bubble:nth-child(1) {\n  width: 60px;\n  height: 60px;\n  bottom: -60px;\n  left: 10%;\n  animation-delay: 0s;\n}\n.bubble:nth-child(2) {\n  width: 80px;\n  height: 80px;\n  bottom: -80px;\n  left: 30%;\n  animation-delay: 1s;\n}\n.bubble:nth-child(3) {\n  width: 40px;\n  height: 40px;\n  bottom: -40px;\n  left: 50%;\n  animation-delay: 2s;\n}\n.bubble:nth-child(4) {\n  width: 70px;\n  height: 70px;\n  bottom: -70px;\n  left: 70%;\n  animation-delay: 1.5s;\n}\n.bubble:nth-child(5) {\n  width: 50px;\n  height: 50px;\n  bottom: -50px;\n  left: 90%;\n  animation-delay: 0.5s;\n}\n@keyframes float {\n  0% {\n    transform: translateY(0) scale(1);\n  }\n  50% {\n    transform: translateY(-250px) scale(1.2);\n  }\n  100% {\n    transform: translateY(0) scale(1);\n  }\n}","\u003Cdiv class=\"bubble-container\">\n  \u003Cdiv class=\"bubble\">\u003C/div>\n  \u003Cdiv class=\"bubble\">\u003C/div>\n  \u003Cdiv class=\"bubble\">\u003C/div>\n  \u003Cdiv class=\"bubble\">\u003C/div>\n  \u003Cdiv class=\"bubble\">\u003C/div>\n\u003C/div>",{"id":212,"category":6,"title":213,"description":214,"author":9,"date":10,"tags":215,"code":218,"html":219,"previewBg":31,"canPreview":19},"css-glitch-text","Glitch Text Effect","Retro glitch text effect with animated distortion",[12,216,38,27,217],"Glitch","Effect",".glitch-text {\n  font-size: 48px;\n  font-weight: 900;\n  position: relative;\n  color: #000;\n  letter-spacing: 2px;\n}\n.glitch-text::before,\n.glitch-text::after {\n  content: attr(data-text);\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n}\n.glitch-text::before {\n  left: 2px;\n  text-shadow: -2px 0 #ff00ff;\n  animation: glitch-anim 3s infinite linear alternate-reverse;\n}\n.glitch-text::after {\n  left: -2px;\n  text-shadow: -2px 0 #00ffff;\n  animation: glitch-anim2 2s infinite linear alternate-reverse;\n}\n@keyframes glitch-anim {\n  0% { clip-path: inset(47% 0 5% 0); }\n  20% { clip-path: inset(59% 0 39% 0); }\n  40% { clip-path: inset(43% 0 1% 0); }\n  60% { clip-path: inset(25% 0 63% 0); }\n  80% { clip-path: inset(53% 0 7% 0); }\n  100% { clip-path: inset(5% 0 79% 0); }\n}\n@keyframes glitch-anim2 {\n  0% { clip-path: inset(65% 0 3% 0); }\n  20% { clip-path: inset(27% 0 69% 0); }\n  40% { clip-path: inset(3% 0 91% 0); }\n  60% { clip-path: inset(61% 0 17% 0); }\n  80% { clip-path: inset(23% 0 49% 0); }\n  100% { clip-path: inset(83% 0 1% 0); }\n}","\u003Ch2 class=\"glitch-text\" data-text=\"GLITCH\">GLITCH\u003C/h2>",{"id":221,"category":6,"title":222,"description":223,"author":9,"date":10,"tags":224,"code":227,"html":228,"previewBg":18,"canPreview":19},"css-scroll-snap","Scroll Snap Container","Smooth scroll snap effect for horizontal/vertical scrolling",[12,111,225,226,15],"Snap","Container",".scroll-snap-container {\n  width: 100%;\n  max-width: 600px;\n  height: 300px;\n  overflow-x: scroll;\n  scroll-snap-type: x mandatory;\n  display: flex;\n  gap: 0;\n  -webkit-overflow-scrolling: touch;\n}\n.scroll-snap-item {\n  flex: 0 0 100%;\n  height: 100%;\n  scroll-snap-align: start;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  font-size: 32px;\n  font-weight: bold;\n  color: white;\n}\n.scroll-snap-item:nth-child(1) { background: #ff6b6b; }\n.scroll-snap-item:nth-child(2) { background: #4ecdc4; }\n.scroll-snap-item:nth-child(3) { background: #ffe66d; }","\u003Cdiv class=\"scroll-snap-container\">\n  \u003Cdiv class=\"scroll-snap-item\">Slide 1\u003C/div>\n  \u003Cdiv class=\"scroll-snap-item\">Slide 2\u003C/div>\n  \u003Cdiv class=\"scroll-snap-item\">Slide 3\u003C/div>\n\u003C/div>",{"id":230,"category":6,"title":231,"description":232,"author":9,"date":10,"tags":233,"code":235,"html":236,"previewBg":18,"canPreview":19},"css-tooltip","Animated CSS Tooltip","Stylish animated tooltip with arrow and fade effect",[12,234,28,27,15],"Tooltip",".tooltip-container {\n  position: relative;\n  display: inline-block;\n  cursor: pointer;\n}\n.tooltip-text {\n  visibility: hidden;\n  width: 120px;\n  background-color: #333;\n  color: #fff;\n  text-align: center;\n  border-radius: 6px;\n  padding: 8px;\n  position: absolute;\n  z-index: 1;\n  bottom: 125%;\n  left: 50%;\n  transform: translateX(-50%);\n  opacity: 0;\n  transition: opacity 0.3s;\n}\n.tooltip-text::after {\n  content: \"\";\n  position: absolute;\n  top: 100%;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 5px;\n  border-style: solid;\n  border-color: #333 transparent transparent transparent;\n}\n.tooltip-container:hover .tooltip-text {\n  visibility: visible;\n  opacity: 1;\n}","\u003Cdiv class=\"tooltip-container\">\n  Hover for tooltip\n  \u003Cspan class=\"tooltip-text\">This is a tooltip!\u003C/span>\n\u003C/div>",{"id":238,"category":6,"title":239,"description":240,"author":9,"date":10,"tags":241,"code":243,"html":244,"previewBg":31,"canPreview":19},"css-fire-animation","CSS Fire Animation","Realistic fire animation effect using gradient and keyframes",[12,242,27,47,58],"Fire",".fire-container {\n  width: 100px;\n  height: 200px;\n  position: relative;\n  margin: 0 auto;\n}\n.fire {\n  position: absolute;\n  bottom: 0;\n  left: 50%;\n  transform: translateX(-50%);\n  width: 80px;\n  height: 150px;\n  background: linear-gradient(to top, #ff4500 0%, #ff8c00 30%, #ffd700 60%, #ffffff 100%);\n  border-radius: 50% 50% 20% 20%;\n  animation: fire-flame 0.8s infinite alternate;\n  opacity: 0.9;\n}\n.fire::before {\n  content: '';\n  position: absolute;\n  width: 100px;\n  height: 120px;\n  background: linear-gradient(to top, #ff8c00 0%, #ffd700 50%, #ffffff 100%);\n  border-radius: 50%;\n  bottom: 10px;\n  left: -10px;\n  animation: fire-glow 1s infinite alternate;\n  opacity: 0.6;\n}\n@keyframes fire-flame {\n  0% { transform: translateX(-50%) scale(1); }\n  100% { transform: translateX(-50%) scale(1.1); }\n}\n@keyframes fire-glow {\n  0% { opacity: 0.5; }\n  100% { opacity: 0.8; }\n}","\u003Cdiv class=\"fire-container\">\n  \u003Cdiv class=\"fire\">\u003C/div>\n\u003C/div>",{"id":246,"category":6,"title":247,"description":248,"author":9,"date":10,"tags":249,"code":252,"html":253,"previewBg":18,"canPreview":19},"css-sticky-header","Animated Sticky Header","Sticky header with shrink animation on scroll",[12,250,251,111,27],"Sticky","Header","/* Add JS: window.addEventListener('scroll', function() { const header = document.querySelector('.sticky-header'); if (window.scrollY > 50) { header.classList.add('shrink'); } else { header.classList.remove('shrink'); } }); */\n.sticky-header {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  background: white;\n  padding: 20px;\n  box-shadow: 0 2px 10px rgba(0,0,0,0.1);\n  transition: all 0.3s ease;\n  z-index: 100;\n}\n.sticky-header.shrink {\n  padding: 10px 20px;\n  box-shadow: 0 4px 15px rgba(0,0,0,0.15);\n}\n.header-content {\n  max-width: 1200px;\n  margin: 0 auto;\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n}\n.header-logo {\n  font-size: 24px;\n  font-weight: bold;\n  color: #333;\n  transition: font-size 0.3s ease;\n}\n.sticky-header.shrink .header-logo {\n  font-size: 20px;\n}","\u003Cheader class=\"sticky-header\">\n  \u003Cdiv class=\"header-content\">\n    \u003Cdiv class=\"header-logo\">Logo\u003C/div>\n    \u003Cnav>Menu\u003C/nav>\n  \u003C/div>\n\u003C/header>\n\u003Cdiv style=\"height: 2000px; padding-top: 100px;\">\n  \u003Ch3>Scroll down to see header shrink\u003C/h3>\n\u003C/div>",{"id":255,"category":6,"title":256,"description":257,"author":9,"date":10,"tags":258,"code":259,"html":260,"previewBg":18,"canPreview":19},"css-gradient-button","Animated Gradient Button","Button with animated gradient background on hover",[12,47,26,27,28],".gradient-button {\n  padding: 12px 32px;\n  border: none;\n  border-radius: 50px;\n  font-size: 16px;\n  font-weight: 600;\n  color: white;\n  cursor: pointer;\n  background: linear-gradient(90deg, #4158d0, #c850c0, #ffcc70);\n  background-size: 200% 200%;\n  transition: all 0.5s ease;\n  box-shadow: 0 4px 15px rgba(0,0,0,0.1);\n}\n.gradient-button:hover {\n  animation: gradient-shift 1s ease infinite;\n  transform: translateY(-2px);\n  box-shadow: 0 6px 20px rgba(0,0,0,0.15);\n}\n@keyframes gradient-shift {\n  0% {\n    background-position: 0% 50%;\n  }\n  50% {\n    background-position: 100% 50%;\n  }\n  100% {\n    background-position: 0% 50%;\n  }\n}","\u003Cbutton class=\"gradient-button\">Gradient Button\u003C/button>",{"id":262,"category":6,"title":263,"description":264,"author":9,"date":10,"tags":265,"code":267,"html":268,"previewBg":18,"canPreview":19},"css-water-wave","Water Wave Animation","Realistic water wave animation using CSS transforms",[12,266,67,27,58],"Water",".water-container {\n  width: 300px;\n  height: 200px;\n  background: #0093e9;\n  border-radius: 16px;\n  position: relative;\n  overflow: hidden;\n}\n.wave {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  width: 200%;\n  height: 100%;\n  background: rgba(255,255,255,0.2);\n  border-radius: 45%;\n  animation: wave-animation 8s linear infinite;\n}\n.wave:nth-child(2) {\n  animation-delay: -4s;\n  opacity: 0.5;\n}\n@keyframes wave-animation {\n  0% {\n    transform: translateX(-50%) rotate(0deg);\n  }\n  100% {\n    transform: translateX(-50%) rotate(360deg);\n  }\n}","\u003Cdiv class=\"water-container\">\n  \u003Cdiv class=\"wave\">\u003C/div>\n  \u003Cdiv class=\"wave\">\u003C/div>\n\u003C/div>",{"id":270,"category":6,"title":271,"description":272,"author":9,"date":10,"tags":273,"code":276,"html":277,"previewBg":18,"canPreview":19},"css-star-rating","Custom Star Rating","Stylish custom star rating component with hover effects",[12,274,275,28,15],"Rating","Star",".star-rating {\n  display: inline-block;\n  font-size: 0;\n}\n.star {\n  font-size: 36px;\n  color: #ddd;\n  cursor: pointer;\n  display: inline-block;\n  transition: color 0.2s ease;\n}\n.star:before {\n  content: '★';\n}\n.star:hover,\n.star:hover ~ .star,\n.star.active,\n.star.active ~ .star {\n  color: #ffd700;\n}\n.star-rating:hover .star {\n  color: #ddd;\n}\n.star-rating:hover .star:hover,\n.star-rating:hover .star:hover ~ .star {\n  color: #ffd700;\n}","\u003Cdiv class=\"star-rating\">\n  \u003Cspan class=\"star active\">\u003C/span>\n  \u003Cspan class=\"star active\">\u003C/span>\n  \u003Cspan class=\"star active\">\u003C/span>\n  \u003Cspan class=\"star\">\u003C/span>\n  \u003Cspan class=\"star\">\u003C/span>\n\u003C/div>",{"id":279,"category":6,"title":280,"description":281,"author":9,"date":10,"tags":282,"code":287,"html":288,"previewBg":289,"canPreview":19},"css-liquid-morph-button","Liquid Morph Button","Ultra-smooth liquid morphing button with bezier curve animations and blob effects",[12,283,284,26,285,286],"Liquid","Morph","Blob","Advanced Animation",".liquid-button {\n  position: relative;\n  width: 200px;\n  height: 60px;\n  border: none;\n  border-radius: 30px;\n  background: linear-gradient(135deg, #74ebd5 0%, #ACB6E5 100%);\n  color: white;\n  font-size: 18px;\n  font-weight: 700;\n  cursor: pointer;\n  overflow: hidden;\n  transition: all 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55);\n}\n.liquid-button::before {\n  content: '';\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 150%;\n  height: 150%;\n  background: rgba(255,255,255,0.2);\n  border-radius: 45%;\n  transform: translate(-50%, -50%) rotate(0deg);\n  animation: liquid-wave 6s linear infinite;\n}\n.liquid-button:hover {\n  transform: scale(1.05);\n  box-shadow: 0 10px 30px rgba(116, 235, 213, 0.4);\n}\n.liquid-button:active {\n  transform: scale(0.98);\n}\n@keyframes liquid-wave {\n  0% { transform: translate(-50%, -50%) rotate(0deg); }\n  100% { transform: translate(-50%, -50%) rotate(360deg); }\n}","\u003Cbutton class=\"liquid-button\">Liquid Morph\u003C/button>","#1a1a2e",{"id":291,"category":6,"title":292,"description":293,"author":9,"date":10,"tags":294,"code":299,"html":300,"previewBg":301,"canPreview":19},"css-holographic-card","Holographic Card","Next-gen holographic card with iridescent sheen and 3D tilt effect",[12,295,296,37,297,298],"Holographic","Iridescent","Tilt","Glassmorphism+","/* Add JS: document.querySelector('.hologram-card').addEventListener('mousemove', (e) => { const rect = e.target.getBoundingClientRect(); const x = (e.clientX - rect.left) / rect.width - 0.5; const y = (e.clientY - rect.top) / rect.height - 0.5; e.target.style.transform = `perspective(1000px) rotateY(${x * 10}deg) rotateX(${-y * 10}deg)`; }); */\n.hologram-card {\n  width: 350px;\n  height: 250px;\n  background: linear-gradient(135deg, rgba(255,255,255,0.1), rgba(255,255,255,0.05));\n  backdrop-filter: blur(15px);\n  -webkit-backdrop-filter: blur(15px);\n  border: 1px solid rgba(255,255,255,0.18);\n  border-radius: 20px;\n  position: relative;\n  overflow: hidden;\n  transition: all 0.3s ease;\n}\n.hologram-card::before {\n  content: '';\n  position: absolute;\n  top: 0;\n  left: -100%;\n  width: 100%;\n  height: 100%;\n  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);\n  background: linear-gradient(90deg, #ff00cc, #3333ff, #00ffcc, #ff00cc);\n  background-size: 400% 400%;\n  opacity: 0.6;\n  animation: hologram-shine 3s linear infinite;\n  mix-blend-mode: lighten;\n}\n@keyframes hologram-shine {\n  0% { background-position: 0% 50%; left: -100%; }\n  100% { background-position: 400% 50%; left: 100%; }\n}","\u003Cdiv class=\"hologram-card\">\u003C/div>","linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%)",{"id":303,"category":6,"title":304,"description":305,"author":9,"date":10,"tags":306,"code":311,"html":312,"previewBg":31,"canPreview":19},"css-advanced-glitch","Advanced Glitch Art","Cinema-quality glitch effect with color separation and scanline overlay",[12,216,307,308,309,310],"Scanline","Color Separation","Cyberpunk","Advanced",".glitch-art-container {\n  position: relative;\n  width: 400px;\n  height: 250px;\n  background: #000;\n  border-radius: 8px;\n  overflow: hidden;\n}\n.glitch-content {\n  width: 100%;\n  height: 100%;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  font-size: 48px;\n  font-weight: 900;\n  color: #fff;\n  text-transform: uppercase;\n  position: relative;\n}\n.glitch-content::before,\n.glitch-content::after {\n  content: attr(data-text);\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n.glitch-content::before {\n  color: #ff00ff;\n  left: 2px;\n  animation: glitch-1 2s infinite linear alternate-reverse;\n}\n.glitch-content::after {\n  color: #00ffff;\n  left: -2px;\n  animation: glitch-2 3s infinite linear alternate-reverse;\n}\n.glitch-art-container::after {\n  content: '';\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: repeating-linear-gradient(transparent, transparent 2px, rgba(0,0,0,0.3) 2px, rgba(0,0,0,0.3) 4px);\n  pointer-events: none;\n  animation: scanline 8s linear infinite;\n}\n@keyframes glitch-1 {\n  0%, 19.999%, 22%, 62.999%, 64%, 64.999%, 70%, 100% { opacity: 1; transform: translate(0); }\n  20%, 21.999%, 63%, 63.999%, 65%, 69.999% { opacity: 0.8; transform: translate(-4px, 4px); }\n}\n@keyframes glitch-2 {\n  0%, 29.999%, 32%, 82.999%, 84%, 84.999%, 90%, 100% { opacity: 1; transform: translate(0); }\n  30%, 31.999%, 83%, 83.999%, 85%, 89.999% { opacity: 0.8; transform: translate(4px, -4px); }\n}\n@keyframes scanline {\n  0% { transform: translateY(-100%); }\n  100% { transform: translateY(100%); }\n}","\u003Cdiv class=\"glitch-art-container\">\n  \u003Cdiv class=\"glitch-content\" data-text=\"CYBERPUNK\">CYBERPUNK\u003C/div>\n\u003C/div>",{"id":314,"category":6,"title":315,"description":316,"author":9,"date":10,"tags":317,"code":321,"html":322,"previewBg":323,"canPreview":19},"css-liquid-metal-text","Liquid Metal Text","Hyper-realistic liquid metal text with flowing chrome effect",[12,318,319,47,320],"Liquid Metal","Chrome","Text Effect",".liquid-metal-text {\n  font-size: 80px;\n  font-weight: 900;\n  text-transform: uppercase;\n  background: linear-gradient(45deg, \n    #ffffff 0%, \n    #e0e0e0 10%, \n    #a0a0a0 20%, \n    #707070 30%, \n    #a0a0a0 40%, \n    #d0d0d0 50%, \n    #ffffff 60%, \n    #a0a0a0 70%, \n    #707070 80%, \n    #a0a0a0 90%, \n    #ffffff 100%);\n  background-size: 200% 200%;\n  -webkit-background-clip: text;\n  background-clip: text;\n  -webkit-text-fill-color: transparent;\n  text-fill-color: transparent;\n  animation: liquid-metal-flow 3s ease-in-out infinite;\n  text-shadow: 0 2px 10px rgba(0,0,0,0.1);\n}\n@keyframes liquid-metal-flow {\n  0% { background-position: 0% 50%; }\n  50% { background-position: 100% 50%; }\n  100% { background-position: 0% 50%; }\n}","\u003Ch1 class=\"liquid-metal-text\">METAL\u003C/h1>","#111",{"id":325,"category":6,"title":326,"description":327,"author":9,"date":10,"tags":328,"code":332,"html":333,"previewBg":334,"canPreview":19},"css-orbital-animation","Orbital Particle Animation","3D orbital particle system with nested rotations and glow effects",[12,37,329,330,27,331],"Orbital","Particles","Space",".orbital-container {\n  width: 300px;\n  height: 300px;\n  perspective: 800px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n.orbital-core {\n  width: 60px;\n  height: 60px;\n  border-radius: 50%;\n  background: radial-gradient(circle, #ff6b81 0%, #ff4757 100%);\n  box-shadow: 0 0 30px rgba(255, 71, 87, 0.8);\n  position: relative;\n  animation: core-pulse 2s infinite ease-in-out;\n}\n.orbital-ring {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform-origin: center;\n  border: 2px solid rgba(108, 99, 255, 0.5);\n  border-radius: 50%;\n  animation: orbit 10s linear infinite;\n}\n.orbital-ring-1 {\n  width: 150px;\n  height: 150px;\n  margin: -75px 0 0 -75px;\n  animation-duration: 8s;\n}\n.orbital-ring-2 {\n  width: 220px;\n  height: 220px;\n  margin: -110px 0 0 -110px;\n  animation-duration: 12s;\n  animation-direction: reverse;\n  border-color: rgba(0, 242, 96, 0.5);\n}\n.orbital-particle {\n  position: absolute;\n  width: 12px;\n  height: 12px;\n  border-radius: 50%;\n  background: #70a1ff;\n  top: -6px;\n  left: 50%;\n  margin-left: -6px;\n  box-shadow: 0 0 15px rgba(112, 161, 255, 0.8);\n}\n.orbital-ring-2 .orbital-particle {\n  background: #2ed573;\n  box-shadow: 0 0 15px rgba(46, 213, 115, 0.8);\n}\n@keyframes orbit {\n  0% { transform: rotateZ(0deg) rotateX(60deg); }\n  100% { transform: rotateZ(360deg) rotateX(60deg); }\n}\n@keyframes core-pulse {\n  0%, 100% { transform: scale(1); box-shadow: 0 0 30px rgba(255, 71, 87, 0.8); }\n  50% { transform: scale(1.1); box-shadow: 0 0 40px rgba(255, 71, 87, 1); }\n}","\u003Cdiv class=\"orbital-container\">\n  \u003Cdiv class=\"orbital-core\">\n    \u003Cdiv class=\"orbital-ring orbital-ring-1\">\n      \u003Cdiv class=\"orbital-particle\">\u003C/div>\n    \u003C/div>\n    \u003Cdiv class=\"orbital-ring orbital-ring-2\">\n      \u003Cdiv class=\"orbital-particle\">\u003C/div>\n    \u003C/div>\n  \u003C/div>\n\u003C/div>","#0a0e17",{"id":336,"category":6,"title":337,"description":338,"author":9,"date":10,"tags":339,"code":342,"html":343,"previewBg":31,"canPreview":19},"css-3d-tunnel-animation","3D Tunnel Animation","Immersive 3D tunnel with infinite scrolling perspective effect",[12,37,340,39,27,341],"Tunnel","Immersive",".tunnel-container {\n  width: 400px;\n  height: 400px;\n  perspective: 100px;\n  overflow: hidden;\n  background: #000;\n  border-radius: 50%;\n}\n.tunnel {\n  width: 100%;\n  height: 100%;\n  position: relative;\n  transform-style: preserve-3d;\n  animation: tunnel-move 8s linear infinite;\n}\n.tunnel-ring {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  border: 4px solid;\n  border-radius: 50%;\n  transform-style: preserve-3d;\n}\n.tunnel-ring-1 { border-color: rgba(255, 0, 255, 0.8); transform: translateZ(-50px); }\n.tunnel-ring-2 { border-color: rgba(0, 255, 255, 0.7); transform: translateZ(-100px); }\n.tunnel-ring-3 { border-color: rgba(255, 255, 0, 0.6); transform: translateZ(-150px); }\n.tunnel-ring-4 { border-color: rgba(0, 255, 0, 0.5); transform: translateZ(-200px); }\n.tunnel-ring-5 { border-color: rgba(0, 0, 255, 0.4); transform: translateZ(-250px); }\n.tunnel-center {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 20px;\n  height: 20px;\n  background: #fff;\n  border-radius: 50%;\n  transform: translate(-50%, -50%);\n  box-shadow: 0 0 20px #fff;\n}\n@keyframes tunnel-move {\n  0% { transform: rotateY(0deg) rotateX(0deg) translateZ(0); }\n  100% { transform: rotateY(360deg) rotateX(10deg) translateZ(50px); }\n}","\u003Cdiv class=\"tunnel-container\">\n  \u003Cdiv class=\"tunnel\">\n    \u003Cdiv class=\"tunnel-ring tunnel-ring-1\">\u003C/div>\n    \u003Cdiv class=\"tunnel-ring tunnel-ring-2\">\u003C/div>\n    \u003Cdiv class=\"tunnel-ring tunnel-ring-3\">\u003C/div>\n    \u003Cdiv class=\"tunnel-ring tunnel-ring-4\">\u003C/div>\n    \u003Cdiv class=\"tunnel-ring tunnel-ring-5\">\u003C/div>\n    \u003Cdiv class=\"tunnel-center\">\u003C/div>\n  \u003C/div>\n\u003C/div>",{"id":345,"category":6,"title":346,"description":347,"author":9,"date":10,"tags":348,"code":352,"html":353,"previewBg":31,"canPreview":19},"css-bloom-effect","Photorealistic Bloom Effect","Advanced bloom/glow effect with multiple blur layers and color grading",[12,349,350,148,351],"Bloom","Glow","Advanced Filter",".bloom-container {\n  width: 300px;\n  height: 300px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  background: #000;\n  border-radius: 16px;\n  position: relative;\n  overflow: hidden;\n}\n.bloom-element {\n  width: 150px;\n  height: 150px;\n  border-radius: 50%;\n  background: radial-gradient(circle, #ffd700 0%, #ff8c00 70%, #ff4500 100%);\n  position: relative;\n  z-index: 2;\n}\n.bloom-layer-1 {\n  position: absolute;\n  width: 150px;\n  height: 150px;\n  border-radius: 50%;\n  background: radial-gradient(circle, #ffd700 0%, #ff8c00 70%, #ff4500 100%);\n  filter: blur(15px);\n  opacity: 0.8;\n  z-index: 1;\n}\n.bloom-layer-2 {\n  position: absolute;\n  width: 200px;\n  height: 200px;\n  border-radius: 50%;\n  background: radial-gradient(circle, #ff8c00 0%, #ff4500 100%);\n  filter: blur(30px);\n  opacity: 0.5;\n  z-index: 0;\n}\n.bloom-layer-3 {\n  position: absolute;\n  width: 250px;\n  height: 250px;\n  border-radius: 50%;\n  background: radial-gradient(circle, #ff4500 0%, #dc143c 100%);\n  filter: blur(45px);\n  opacity: 0.3;\n  z-index: 0;\n}\n.bloom-container::after {\n  content: '';\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: linear-gradient(45deg, rgba(255,0,0,0.2), rgba(255,255,0,0.2));\n  mix-blend-mode: screen;\n  pointer-events: none;\n}","\u003Cdiv class=\"bloom-container\">\n  \u003Cdiv class=\"bloom-element\">\u003C/div>\n  \u003Cdiv class=\"bloom-layer-1\">\u003C/div>\n  \u003Cdiv class=\"bloom-layer-2\">\u003C/div>\n  \u003Cdiv class=\"bloom-layer-3\">\u003C/div>\n\u003C/div>",{"id":355,"category":6,"title":356,"description":357,"author":9,"date":10,"tags":358,"code":361,"html":362,"previewBg":363,"canPreview":19},"css-cloth-simulation","CSS Cloth Simulation","Physics-based cloth simulation effect with wave animations",[12,359,360,67,286],"Cloth","Physics",".cloth-container {\n  width: 400px;\n  height: 300px;\n  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n  border-radius: 16px;\n  position: relative;\n  overflow: hidden;\n}\n.cloth-strip {\n  position: absolute;\n  width: 100%;\n  height: 20px;\n  background: rgba(255,255,255,0.1);\n  backdrop-filter: blur(5px);\n  border-radius: 10px;\n  animation: cloth-wave 3s ease-in-out infinite;\n}\n.cloth-strip:nth-child(1) { top: 20%; animation-delay: 0s; }\n.cloth-strip:nth-child(2) { top: 35%; animation-delay: 0.2s; }\n.cloth-strip:nth-child(3) { top: 50%; animation-delay: 0.4s; }\n.cloth-strip:nth-child(4) { top: 65%; animation-delay: 0.6s; }\n.cloth-strip:nth-child(5) { top: 80%; animation-delay: 0.8s; }\n@keyframes cloth-wave {\n  0%, 100% { transform: translateX(0) scaleX(1); }\n  25% { transform: translateX(-15px) scaleX(1.05); }\n  50% { transform: translateX(0) scaleX(1); }\n  75% { transform: translateX(15px) scaleX(1.05); }\n}","\u003Cdiv class=\"cloth-container\">\n  \u003Cdiv class=\"cloth-strip\">\u003C/div>\n  \u003Cdiv class=\"cloth-strip\">\u003C/div>\n  \u003Cdiv class=\"cloth-strip\">\u003C/div>\n  \u003Cdiv class=\"cloth-strip\">\u003C/div>\n  \u003Cdiv class=\"cloth-strip\">\u003C/div>\n\u003C/div>","#f8f9fa",{"id":365,"category":6,"title":366,"description":367,"author":9,"date":10,"tags":368,"code":370,"html":371,"previewBg":31,"canPreview":19},"css-neon-grid","Animated Neon Grid","Cyberpunk-style neon grid with scanning laser and pulse effects",[12,25,84,309,369,27],"Laser",".neon-grid-container {\n  width: 400px;\n  height: 400px;\n  background: #000;\n  position: relative;\n  overflow: hidden;\n  border-radius: 8px;\n}\n.neon-grid {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-image: \n    linear-gradient(to right, rgba(0, 255, 255, 0.1) 1px, transparent 1px),\n    linear-gradient(to bottom, rgba(0, 255, 255, 0.1) 1px, transparent 1px);\n  background-size: 40px 40px;\n  animation: grid-pulse 4s infinite ease-in-out;\n}\n.neon-laser {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 4px;\n  height: 100%;\n  background: linear-gradient(to bottom, transparent, #00ffff, transparent);\n  box-shadow: 0 0 20px #00ffff;\n  animation: laser-scan 8s linear infinite;\n}\n.neon-dot {\n  position: absolute;\n  width: 8px;\n  height: 8px;\n  border-radius: 50%;\n  background: #ff00ff;\n  box-shadow: 0 0 15px #ff00ff;\n  animation: dot-pulse 2s infinite ease-in-out;\n}\n.neon-dot:nth-child(1) { top: 20%; left: 30%; animation-delay: 0s; }\n.neon-dot:nth-child(2) { top: 60%; left: 70%; animation-delay: 0.5s; }\n.neon-dot:nth-child(3) { top: 80%; left: 40%; animation-delay: 1s; }\n@keyframes grid-pulse {\n  0%, 100% { opacity: 0.5; }\n  50% { opacity: 1; }\n}\n@keyframes laser-scan {\n  0% { left: 0%; }\n  50% { left: 100%; }\n  100% { left: 0%; }\n}\n@keyframes dot-pulse {\n  0%, 100% { transform: scale(1); opacity: 0.7; }\n  50% { transform: scale(1.5); opacity: 1; }\n}","\u003Cdiv class=\"neon-grid-container\">\n  \u003Cdiv class=\"neon-grid\">\u003C/div>\n  \u003Cdiv class=\"neon-laser\">\u003C/div>\n  \u003Cdiv class=\"neon-dot\">\u003C/div>\n  \u003Cdiv class=\"neon-dot\">\u003C/div>\n  \u003Cdiv class=\"neon-dot\">\u003C/div>\n\u003C/div>",{"id":373,"category":6,"title":374,"description":375,"author":9,"date":10,"tags":376,"code":381,"html":382,"previewBg":31,"canPreview":19},"css-volumetric-light","Volumetric Light Rays","Cinema-quality godrays/volumetric light effect with depth",[12,377,378,379,380],"Volumetric Light","Godrays","Depth","Advanced Effect",".volumetric-container {\n  width: 400px;\n  height: 300px;\n  background: #0a0a1a;\n  position: relative;\n  overflow: hidden;\n  border-radius: 16px;\n}\n.light-source {\n  position: absolute;\n  top: -50px;\n  right: -50px;\n  width: 200px;\n  height: 200px;\n  border-radius: 50%;\n  background: radial-gradient(circle, #fff 0%, #ffd700 50%, transparent 70%);\n  filter: blur(20px);\n  opacity: 0.9;\n}\n.light-ray {\n  position: absolute;\n  top: 0;\n  right: 0;\n  width: 100%;\n  height: 100%;\n  background: linear-gradient(45deg, transparent 30%, rgba(255, 215, 0, 0.1) 70%, transparent 90%);\n  clip-path: polygon(100% 0%, 0% 100%, 100% 100%);\n  animation: light-flicker 6s infinite ease-in-out;\n}\n.light-ray:nth-child(2) {\n  background: linear-gradient(60deg, transparent 20%, rgba(255, 255, 255, 0.05) 60%, transparent 80%);\n  animation-delay: 1s;\n}\n.light-ray:nth-child(3) {\n  background: linear-gradient(30deg, transparent 40%, rgba(255, 165, 0, 0.08) 80%, transparent 95%);\n  animation-delay: 2s;\n}\n.dust-particle {\n  position: absolute;\n  width: 2px;\n  height: 2px;\n  background: #fff;\n  border-radius: 50%;\n  animation: dust-float 8s infinite linear;\n}\n.dust-particle:nth-child(4) { top: 20%; left: 70%; animation-delay: 0s; }\n.dust-particle:nth-child(5) { top: 40%; left: 80%; animation-delay: 1s; }\n.dust-particle:nth-child(6) { top: 60%; left: 60%; animation-delay: 2s; }\n.dust-particle:nth-child(7) { top: 80%; left: 75%; animation-delay: 3s; }\n@keyframes light-flicker {\n  0%, 100% { opacity: 0.6; }\n  50% { opacity: 1; }\n}\n@keyframes dust-float {\n  0% { transform: translate(0, 0) rotate(0deg); opacity: 0; }\n  10% { opacity: 1; }\n  90% { opacity: 1; }\n  100% { transform: translate(-50px, 50px) rotate(180deg); opacity: 0; }\n}","\u003Cdiv class=\"volumetric-container\">\n  \u003Cdiv class=\"light-source\">\u003C/div>\n  \u003Cdiv class=\"light-ray\">\u003C/div>\n  \u003Cdiv class=\"light-ray\">\u003C/div>\n  \u003Cdiv class=\"light-ray\">\u003C/div>\n  \u003Cdiv class=\"dust-particle\">\u003C/div>\n  \u003Cdiv class=\"dust-particle\">\u003C/div>\n  \u003Cdiv class=\"dust-particle\">\u003C/div>\n  \u003Cdiv class=\"dust-particle\">\u003C/div>\n\u003C/div>",{"id":384,"category":6,"title":385,"description":386,"author":9,"date":10,"tags":387,"code":391,"html":392,"previewBg":393,"canPreview":19},"css-plasma-animation","Plasma Energy Animation","Dynamic plasma energy effect with swirling color gradients and high contrast",[12,388,389,47,390],"Plasma","Energy","High Contrast",".plasma-container {\n  width: 400px;\n  height: 300px;\n  position: relative;\n  overflow: hidden;\n  border-radius: 16px;\n}\n.plasma-core {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 150px;\n  height: 150px;\n  transform: translate(-50%, -50%);\n  border-radius: 50%;\n  background: radial-gradient(circle, #ff00ff 0%, #00ffff 100%);\n  filter: blur(10px);\n  animation: plasma-pulse 3s infinite ease-in-out;\n}\n.plasma-wave {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  height: 200px;\n  transform: translate(-50%, -50%);\n  border-radius: 45%;\n  background: linear-gradient(45deg, #ff00ff, #00ffff, #ff00ff);\n  background-size: 400% 400%;\n  opacity: 0.6;\n  filter: blur(20px);\n  animation: plasma-swirl 8s infinite linear;\n}\n@keyframes plasma-pulse {\n  0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 1; }\n  50% { transform: translate(-50%, -50%) scale(1.2); opacity: 0.8; }\n}\n@keyframes plasma-swirl {\n  0% { background-position: 0% 50%; transform: translate(-50%, -50%) rotate(0deg); }\n  100% { background-position: 400% 50%; transform: translate(-50%, -50%) rotate(360deg); }\n}","\u003Cdiv class=\"plasma-container\">\n  \u003Cdiv class=\"plasma-core\">\u003C/div>\n  \u003Cdiv class=\"plasma-wave\">\u003C/div>\n\u003C/div>","#000000",{"id":395,"category":6,"title":396,"description":397,"author":9,"date":10,"tags":398,"code":401,"html":402,"previewBg":403,"canPreview":19},"css-neon-text-reveal","Neon Text Reveal Animation","High-contrast neon text reveal with sliding mask effect",[12,25,399,400,390],"Text Reveal","Mask",".neon-reveal-container {\n  position: relative;\n  width: 100%;\n  max-width: 500px;\n  height: 100px;\n  overflow: hidden;\n}\n.neon-reveal-text {\n  font-size: 64px;\n  font-weight: 900;\n  text-transform: uppercase;\n  color: #ffffff;\n  position: relative;\n  line-height: 100px;\n  letter-spacing: 2px;\n}\n.neon-reveal-text::before {\n  content: attr(data-text);\n  position: absolute;\n  top: 0;\n  left: 0;\n  color: #00ff9d;\n  text-shadow: 0 0 10px #00ff9d, 0 0 20px #00ff9d, 0 0 40px #00ff9d;\n  width: 0;\n  height: 100%;\n  overflow: hidden;\n  animation: text-reveal 3s forwards ease-in-out;\n}\n@keyframes text-reveal {\n  0% { width: 0; }\n  100% { width: 100%; }\n}","\u003Cdiv class=\"neon-reveal-container\">\n  \u003Cdiv class=\"neon-reveal-text\" data-text=\"REVEAL\">REVEAL\u003C/div>\n\u003C/div>","#1a1a1a",{"id":405,"category":6,"title":406,"description":407,"author":9,"date":10,"tags":408,"code":411,"html":412,"previewBg":413,"canPreview":19},"css-3d-glass-cube","3D Glass Cube with Reflection","High-contrast 3D glass cube with reflective surfaces and shadow",[12,37,409,410,390],"Glass Cube","Reflection",".cube-3d-container {\n  width: 300px;\n  height: 300px;\n  perspective: 1000px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n.glass-cube {\n  width: 200px;\n  height: 200px;\n  position: relative;\n  transform-style: preserve-3d;\n  animation: cube-spin 15s infinite linear;\n}\n.cube-face-3d {\n  position: absolute;\n  width: 200px;\n  height: 200px;\n  background: rgba(255, 255, 255, 0.15);\n  backdrop-filter: blur(10px);\n  border: 1px solid rgba(255, 255, 255, 0.3);\n  box-shadow: 0 0 30px rgba(255, 255, 255, 0.2);\n}\n.face-front-3d { transform: translateZ(100px); }\n.face-back-3d { transform: rotateY(180deg) translateZ(100px); }\n.face-right-3d { transform: rotateY(90deg) translateZ(100px); }\n.face-left-3d { transform: rotateY(-90deg) translateZ(100px); }\n.face-top-3d { transform: rotateX(90deg) translateZ(100px); }\n.face-bottom-3d { transform: rotateX(-90deg) translateZ(100px); }\n@keyframes cube-spin {\n  0% { transform: rotateX(0deg) rotateY(0deg); }\n  100% { transform: rotateX(360deg) rotateY(360deg); }\n}","\u003Cdiv class=\"cube-3d-container\">\n  \u003Cdiv class=\"glass-cube\">\n    \u003Cdiv class=\"cube-face-3d face-front-3d\">\u003C/div>\n    \u003Cdiv class=\"cube-face-3d face-back-3d\">\u003C/div>\n    \u003Cdiv class=\"cube-face-3d face-right-3d\">\u003C/div>\n    \u003Cdiv class=\"cube-face-3d face-left-3d\">\u003C/div>\n    \u003Cdiv class=\"cube-face-3d face-top-3d\">\u003C/div>\n    \u003Cdiv class=\"cube-face-3d face-bottom-3d\">\u003C/div>\n  \u003C/div>\n\u003C/div>","#2d3436",{"id":415,"category":6,"title":416,"description":417,"author":9,"date":10,"tags":418,"code":421,"html":422,"previewBg":393,"canPreview":19},"css-pixel-explosion","Pixel Explosion Animation","High-contrast pixel explosion effect with vibrant colors on dark background",[12,419,420,27,390],"Pixel","Explosion",".pixel-explosion-container {\n  width: 400px;\n  height: 300px;\n  position: relative;\n  overflow: hidden;\n  border-radius: 8px;\n}\n.pixel {\n  position: absolute;\n  width: 8px;\n  height: 8px;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  border-radius: 2px;\n  animation: pixel-burst 2s infinite ease-out;\n}\n.pixel:nth-child(1) { background: #ff0000; animation-delay: 0s; }\n.pixel:nth-child(2) { background: #ff9900; animation-delay: 0.1s; }\n.pixel:nth-child(3) { background: #ffff00; animation-delay: 0.2s; }\n.pixel:nth-child(4) { background: #00ff00; animation-delay: 0.3s; }\n.pixel:nth-child(5) { background: #00ffff; animation-delay: 0.4s; }\n.pixel:nth-child(6) { background: #0000ff; animation-delay: 0.5s; }\n.pixel:nth-child(7) { background: #9900ff; animation-delay: 0.6s; }\n.pixel:nth-child(8) { background: #ff00ff; animation-delay: 0.7s; }\n@keyframes pixel-burst {\n  0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }\n  100% { \n    transform: translate(\n      calc(-50% + (random() * 200 - 100)px), \n      calc(-50% + (random() * 200 - 100)px)\n    ) scale(0); \n    opacity: 0; \n  }\n}","\u003Cdiv class=\"pixel-explosion-container\">\n  \u003Cdiv class=\"pixel\">\u003C/div>\n  \u003Cdiv class=\"pixel\">\u003C/div>\n  \u003Cdiv class=\"pixel\">\u003C/div>\n  \u003Cdiv class=\"pixel\">\u003C/div>\n  \u003Cdiv class=\"pixel\">\u003C/div>\n  \u003Cdiv class=\"pixel\">\u003C/div>\n  \u003Cdiv class=\"pixel\">\u003C/div>\n  \u003Cdiv class=\"pixel\">\u003C/div>\n\u003C/div>",{"id":424,"category":6,"title":425,"description":426,"author":9,"date":10,"tags":427,"code":430,"html":431,"previewBg":432,"canPreview":19},"css-highlight-border-animation","Highlight Border Animation","High-contrast animated border with glowing highlight effect",[12,428,429,350,390],"Border Animation","Highlight",".highlight-card {\n  width: 350px;\n  height: 200px;\n  background: #121212;\n  border-radius: 12px;\n  position: relative;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #ffffff;\n  font-size: 24px;\n  font-weight: 600;\n  overflow: hidden;\n}\n.highlight-card::before {\n  content: '';\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  border: 2px solid transparent;\n  border-radius: 12px;\n  background: linear-gradient(45deg, #76ff03, #00e676) border-box;\n  -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);\n  -webkit-mask-composite: xor;\n  mask-composite: exclude;\n  pointer-events: none;\n}\n.highlight-card::after {\n  content: '';\n  position: absolute;\n  top: -50%;\n  left: -50%;\n  width: 200%;\n  height: 200%;\n  background: linear-gradient(\n    to right, \n    transparent, \n    rgba(255, 255, 255, 0.2), \n    transparent\n  );\n  transform: rotate(45deg);\n  animation: highlight-slide 3s infinite linear;\n}\n@keyframes highlight-slide {\n  0% { transform: rotate(45deg) translateX(-100%); }\n  100% { transform: rotate(45deg) translateX(100%); }\n}","\u003Cdiv class=\"highlight-card\">Highlight Border\u003C/div>","#1e1e1e",{"id":434,"category":6,"title":435,"description":436,"author":9,"date":10,"tags":437,"code":439,"html":440,"previewBg":393,"canPreview":19},"css-contrast-bounce-grid","High Contrast Bounce Grid","Vibrant bouncing shapes on high-contrast background with sync animation",[12,140,84,438,390],"Sync Animation",".bounce-grid-container {\n  width: 400px;\n  height: 300px;\n  display: grid;\n  grid-template-columns: repeat(4, 1fr);\n  grid-template-rows: repeat(3, 1fr);\n  gap: 8px;\n  padding: 16px;\n  border-radius: 8px;\n}\n.bounce-cell {\n  border-radius: 8px;\n  background: #ffffff;\n  animation: cell-bounce 1.5s infinite ease-in-out;\n}\n.bounce-cell:nth-child(odd) { background: #ff3d00; }\n.bounce-cell:nth-child(even) { background: #00b8d4; }\n.bounce-cell:nth-child(1) { animation-delay: 0s; }\n.bounce-cell:nth-child(2) { animation-delay: 0.1s; }\n.bounce-cell:nth-child(3) { animation-delay: 0.2s; }\n.bounce-cell:nth-child(4) { animation-delay: 0.3s; }\n.bounce-cell:nth-child(5) { animation-delay: 0.4s; }\n.bounce-cell:nth-child(6) { animation-delay: 0.5s; }\n.bounce-cell:nth-child(7) { animation-delay: 0.6s; }\n.bounce-cell:nth-child(8) { animation-delay: 0.7s; }\n.bounce-cell:nth-child(9) { animation-delay: 0.8s; }\n.bounce-cell:nth-child(10) { animation-delay: 0.9s; }\n.bounce-cell:nth-child(11) { animation-delay: 1.0s; }\n.bounce-cell:nth-child(12) { animation-delay: 1.1s; }\n@keyframes cell-bounce {\n  0%, 100% { transform: scale(1); }\n  50% { transform: scale(0.7); opacity: 0.8; }\n}","\u003Cdiv class=\"bounce-grid-container\">\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n  \u003Cdiv class=\"bounce-cell\">\u003C/div>\n\u003C/div>",{"id":442,"category":6,"title":443,"description":444,"author":9,"date":10,"tags":445,"code":447,"html":448,"previewBg":449,"canPreview":19},"css-glowing-particles","Glowing Particles on Dark Background","High-contrast glowing particles with trailing light effects",[12,330,350,446,390],"Trail",".particles-container {\n  width: 400px;\n  height: 300px;\n  position: relative;\n  overflow: hidden;\n  border-radius: 12px;\n}\n.glow-particle {\n  position: absolute;\n  border-radius: 50%;\n  background: #ffffff;\n  box-shadow: 0 0 10px #ffffff, 0 0 20px #ffffff;\n  animation: particle-float 6s infinite linear;\n}\n.glow-particle:nth-child(1) {\n  width: 8px; height: 8px;\n  top: 20%; left: 30%;\n  background: #00ffff;\n  box-shadow: 0 0 10px #00ffff, 0 0 20px #00ffff;\n  animation-delay: 0s;\n}\n.glow-particle:nth-child(2) {\n  width: 10px; height: 10px;\n  top: 60%; left: 70%;\n  background: #ff00ff;\n  box-shadow: 0 0 10px #ff00ff, 0 0 20px #ff00ff;\n  animation-delay: 1s;\n}\n.glow-particle:nth-child(3) {\n  width: 6px; height: 6px;\n  top: 40%; left: 80%;\n  background: #ffff00;\n  box-shadow: 0 0 10px #ffff00, 0 0 20px #ffff00;\n  animation-delay: 2s;\n}\n.glow-particle:nth-child(4) {\n  width: 12px; height: 12px;\n  top: 80%; left: 20%;\n  background: #00ff00;\n  box-shadow: 0 0 10px #00ff00, 0 0 20px #00ff00;\n  animation-delay: 3s;\n}\n@keyframes particle-float {\n  0% {\n    transform: translate(0, 0) rotate(0deg);\n    opacity: 1;\n  }\n  25% {\n    transform: translate(50px, -30px) rotate(90deg);\n    opacity: 0.8;\n  }\n  50% {\n    transform: translate(100px, 20px) rotate(180deg);\n    opacity: 0.6;\n  }\n  75% {\n    transform: translate(50px, 50px) rotate(270deg);\n    opacity: 0.8;\n  }\n  100% {\n    transform: translate(0, 0) rotate(360deg);\n    opacity: 1;\n  }\n}","\u003Cdiv class=\"particles-container\">\n  \u003Cdiv class=\"glow-particle\">\u003C/div>\n  \u003Cdiv class=\"glow-particle\">\u003C/div>\n  \u003Cdiv class=\"glow-particle\">\u003C/div>\n  \u003Cdiv class=\"glow-particle\">\u003C/div>\n\u003C/div>","#0a0a0a",{"id":451,"category":6,"title":452,"description":453,"author":9,"date":10,"tags":454,"code":458,"html":459,"previewBg":393,"canPreview":19},"css-contrast-text-shadow","Extreme Contrast Text Shadow","Ultra-bold text with high-contrast multi-layer shadow effect",[12,455,390,456,457],"Text Shadow","Bold","Typography",".contrast-text {\n  font-size: 72px;\n  font-weight: 900;\n  text-transform: uppercase;\n  color: #ffffff;\n  text-align: center;\n  letter-spacing: 4px;\n  text-shadow: \n    0 0 5px #000000,\n    0 0 10px #000000,\n    0 0 15px #000000,\n    0 0 20px #ff0000,\n    0 0 30px #ff0000,\n    0 0 40px #ff0000,\n    0 0 50px #ff0000,\n    0 0 75px #ff0000;\n  animation: text-pulse 2s infinite ease-in-out;\n}\n@keyframes text-pulse {\n  0%, 100% { text-shadow: 0 0 5px #000, 0 0 10px #000, 0 0 15px #000, 0 0 20px #ff0000, 0 0 30px #ff0000, 0 0 40px #ff0000, 0 0 50px #ff0000, 0 0 75px #ff0000; }\n  50% { text-shadow: 0 0 5px #000, 0 0 10px #000, 0 0 15px #000, 0 0 20px #ff4500, 0 0 30px #ff4500, 0 0 40px #ff4500, 0 0 50px #ff4500, 0 0 85px #ff4500; }\n}","\u003Ch1 class=\"contrast-text\">CONTRAST\u003C/h1>",{"id":461,"category":6,"title":462,"description":463,"author":9,"date":10,"tags":464,"code":466,"html":467,"previewBg":468,"canPreview":19},"css-animated-gradient-border","Animated Gradient Border Card","High-contrast card with animated gradient border on neutral background",[12,465,27,390],"Gradient Border",".gradient-border-card-contrast {\n  width: 350px;\n  height: 220px;\n  background: #ffffff;\n  border-radius: 16px;\n  padding: 24px;\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  box-sizing: border-box;\n}\n.gradient-border-card-contrast::before {\n  content: '';\n  position: absolute;\n  top: -2px;\n  left: -2px;\n  right: -2px;\n  bottom: -2px;\n  background: linear-gradient(45deg, #ff0000, #ff9900, #33cc33, #3399ff, #cc33ff, #ff0000);\n  background-size: 400% 400%;\n  border-radius: 18px;\n  z-index: -1;\n  animation: gradient-rotate 8s linear infinite;\n}\n.gradient-border-card-contrast h3 {\n  font-size: 28px;\n  color: #222222;\n  margin: 0 0 12px 0;\n  font-weight: 700;\n}\n.gradient-border-card-contrast p {\n  font-size: 16px;\n  color: #555555;\n  margin: 0;\n  line-height: 1.5;\n}\n@keyframes gradient-rotate {\n  0% { background-position: 0% 50%; }\n  50% { background-position: 100% 50%; }\n  100% { background-position: 0% 50%; }\n}","\u003Cdiv class=\"gradient-border-card-contrast\">\n  \u003Ch3>Gradient Border\u003C/h3>\n  \u003Cp>High contrast animated gradient border with clean white background\u003C/p>\n\u003C/div>","#f0f0f0",{"id":470,"category":6,"title":471,"description":472,"author":9,"date":10,"tags":473,"code":475,"html":476,"previewBg":477,"canPreview":19},"css-dark-mode-toggle","High Contrast Dark Mode Toggle","Ultra high-contrast dark/light mode toggle with smooth animation",[12,122,474,390,27],"Dark Mode",".contrast-toggle-container {\n  width: 80px;\n  height: 40px;\n  position: relative;\n  display: inline-block;\n}\n.contrast-toggle-input {\n  opacity: 0;\n  width: 0;\n  height: 0;\n}\n.contrast-toggle-slider {\n  position: absolute;\n  cursor: pointer;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  background-color: #111111;\n  transition: .4s;\n  border-radius: 40px;\n  border: 2px solid #ffffff;\n}\n.contrast-toggle-slider:before {\n  position: absolute;\n  content: \"\";\n  height: 28px;\n  width: 28px;\n  left: 4px;\n  bottom: 4px;\n  background-color: #ffffff;\n  transition: .4s;\n  border-radius: 50%;\n  box-shadow: 0 0 10px rgba(255, 255, 255, 0.8);\n}\n.contrast-toggle-input:checked + .contrast-toggle-slider {\n  background-color: #ffffff;\n  border: 2px solid #111111;\n}\n.contrast-toggle-input:checked + .contrast-toggle-slider:before {\n  transform: translateX(40px);\n  background-color: #111111;\n  box-shadow: 0 0 10px rgba(0, 0, 0, 0.8);\n}\n.contrast-toggle-slider .sun {\n  position: absolute;\n  top: 50%;\n  left: 8px;\n  transform: translateY(-50%);\n  color: #ffffff;\n  font-size: 18px;\n}\n.contrast-toggle-slider .moon {\n  position: absolute;\n  top: 50%;\n  right: 8px;\n  transform: translateY(-50%);\n  color: #111111;\n  font-size: 18px;\n  opacity: 0;\n  transition: opacity 0.4s;\n}\n.contrast-toggle-input:checked + .contrast-toggle-slider .sun { opacity: 0; }\n.contrast-toggle-input:checked + .contrast-toggle-slider .moon { opacity: 1; }","\u003Clabel class=\"contrast-toggle-container\">\n  \u003Cinput type=\"checkbox\" class=\"contrast-toggle-input\">\n  \u003Cspan class=\"contrast-toggle-slider\">\n    \u003Cspan class=\"sun\">☀\u003C/span>\n    \u003Cspan class=\"moon\">🌙\u003C/span>\n  \u003C/span>\n\u003C/label>","#808080",{"id":479,"category":480,"title":481,"description":482,"author":9,"date":10,"tags":483,"code":487,"canPreview":488},"ts-debounce-function","typescript","Debounce Function","Generic debounce function with immediate execution option",[484,485,486],"TypeScript","Utility","Performance","interface DebounceOptions {\n  immediate?: boolean;\n  maxWait?: number;\n}\n\nfunction debounce\u003CT extends (...args: any[]) => any>(\n  func: T,\n  wait: number,\n  options: DebounceOptions = {}\n): {\n  (...args: Parameters\u003CT>): ReturnType\u003CT> | undefined;\n  cancel: () => void;\n  flush: () => ReturnType\u003CT> | undefined;\n} {\n  const { immediate = false } = options;\n  let timeoutId: ReturnType\u003Ctypeof setTimeout> | null = null;\n  let lastArgs: Parameters\u003CT> | null = null;\n  let lastCallTime: number | null = null;\n  let result: ReturnType\u003CT> | undefined;\n  \n  const later = () => {\n    const timeSinceLastCall = Date.now() - (lastCallTime || 0);\n    \n    if (timeSinceLastCall \u003C wait && timeSinceLastCall >= 0) {\n      timeoutId = setTimeout(later, wait - timeSinceLastCall);\n    } else {\n      timeoutId = null;\n      if (!immediate) {\n        result = lastArgs ? func(...lastArgs) : undefined;\n        lastArgs = null;\n      }\n    }\n  };\n  \n  const debounced = (...args: Parameters\u003CT>): ReturnType\u003CT> | undefined => {\n    lastArgs = args;\n    lastCallTime = Date.now();\n    \n    const callNow = immediate && !timeoutId;\n    \n    if (!timeoutId) {\n      timeoutId = setTimeout(later, wait);\n    }\n    \n    if (callNow) {\n      result = func(...args);\n    }\n    \n    return result;\n  };\n  \n  debounced.cancel = () => {\n    if (timeoutId) {\n      clearTimeout(timeoutId);\n      timeoutId = null;\n      lastArgs = null;\n    }\n  };\n  \n  debounced.flush = () => {\n    if (timeoutId) {\n      clearTimeout(timeoutId);\n      later();\n    }\n    return result;\n  };\n  \n  return debounced;\n}\n\n// Usage examples\nconst searchHandler = debounce((query: string) => {\n  console.log('Searching for:', query);\n  return `Results for: ${query}`;\n}, 300);\n\nconst saveHandler = debounce(\n  (data: Record\u003Cstring, any>) => {\n    console.log('Saving data:', data);\n  },\n  500,\n  { immediate: true }\n);",false,{"id":490,"category":480,"title":491,"description":492,"author":9,"date":10,"tags":493,"code":496,"canPreview":488},"ts-safe-type-guards","Type Safe Guards","Comprehensive runtime type checking utilities",[484,494,495],"Type Safety","Validation","// Basic type guards\nconst isString = (value: unknown): value is string => {\n  return typeof value === 'string';\n};\n\nconst isNumber = (value: unknown): value is number => {\n  return typeof value === 'number' && !isNaN(value);\n};\n\nconst isBoolean = (value: unknown): value is boolean => {\n  return typeof value === 'boolean';\n};\n\nconst isObject = (value: unknown): value is Record\u003Cstring, unknown> => {\n  return value !== null && typeof value === 'object' && !Array.isArray(value);\n};\n\nconst isArray = \u003CT>(value: unknown, guard?: (item: unknown) => item is T): value is T[] => {\n  if (!Array.isArray(value)) return false;\n  if (!guard) return true;\n  return value.every(guard);\n};\n\n// Union type guard\nconst isUnion = \u003CT extends readonly unknown[]>(\n  value: unknown,\n  guards: { [K in keyof T]: (v: unknown) => v is T[K] }\n): value is T[number] => {\n  return guards.some(guard => guard(value));\n};\n\n// Schema validation\ninterface Schema {\n  [key: string]: (value: unknown) => boolean;\n}\n\nconst validateSchema = (value: unknown, schema: Schema): value is Record\u003Cstring, unknown> => {\n  if (!isObject(value)) return false;\n  \n  for (const [key, validator] of Object.entries(schema)) {\n    if (!(key in value) || !validator(value[key])) {\n      return false;\n    }\n  }\n  return true;\n};\n\n// Usage examples\ntype User = {\n  id: number;\n  name: string;\n  email: string;\n  age?: number;\n};\n\nconst isUser = (value: unknown): value is User => {\n  return validateSchema(value, {\n    id: isNumber,\n    name: isString,\n    email: isString,\n    age: (v): v is number => v === undefined || isNumber(v)\n  });\n};\n\n// Parse with validation\nfunction parseJSON\u003CT>(json: string, guard: (value: unknown) => value is T): T | null {\n  try {\n    const parsed = JSON.parse(json);\n    return guard(parsed) ? parsed : null;\n  } catch {\n    return null;\n  }\n}\n\n// Runtime type checking\nconst data: unknown = { id: 1, name: 'John', email: 'john@example.com' };\nif (isUser(data)) {\n  console.log(data.name); // Type safe access\n}",{"id":498,"category":480,"title":499,"description":500,"author":9,"date":10,"tags":501,"code":504,"canPreview":488},"ts-deep-partial","Deep Partial Utility","Recursive Partial type for nested objects",[484,502,503],"Utility Types","Advanced Types","// Basic DeepPartial type\ntype DeepPartial\u003CT> = T extends object\n  ? {\n      [P in keyof T]?: DeepPartial\u003CT[P]>;\n    }\n  : T;\n\n// With arrays and functions support\ntype DeepPartialEnhanced\u003CT> = T extends Function\n  ? T\n  : T extends Array\u003Cinfer U>\n  ? Array\u003CDeepPartialEnhanced\u003CU>>\n  : T extends object\n  ? {\n      [P in keyof T]?: DeepPartialEnhanced\u003CT[P]>;\n    }\n  : Partial\u003CT>;\n\n// Deep Required counterpart\ntype DeepRequired\u003CT> = T extends object\n  ? {\n      [P in keyof T]-?: DeepRequired\u003CT[P]>;\n    }\n  : NonNullable\u003CT>;\n\n// Deep Readonly\ntype DeepReadonly\u003CT> = T extends Function\n  ? T\n  : T extends object\n  ? {\n      readonly [P in keyof T]: DeepReadonly\u003CT[P]>;\n    }\n  : Readonly\u003CT>;\n\n// Merge utility type\ntype Merge\u003CF, S> = {\n  [K in keyof F | keyof S]: K extends keyof S\n    ? S[K]\n    : K extends keyof F\n    ? F[K]\n    : never;\n};\n\n// Usage examples\ninterface UserProfile {\n  id: number;\n  details: {\n    name: string;\n    address: {\n      street: string;\n      city: string;\n      country: string;\n    };\n    preferences: {\n      theme: 'light' | 'dark';\n      notifications: boolean;\n    };\n  };\n  tags: string[];\n}\n\n// Deep partial allows nested optional properties\nconst updateData: DeepPartial\u003CUserProfile> = {\n  details: {\n    address: {\n      city: 'New York'\n    }\n  }\n};\n\n// Deep required makes everything required\nconst completeData: DeepRequired\u003CUserProfile> = {\n  id: 1,\n  details: {\n    name: 'John',\n    address: {\n      street: '123 Main St',\n      city: 'NYC',\n      country: 'USA'\n    },\n    preferences: {\n      theme: 'dark',\n      notifications: true\n    }\n  },\n  tags: ['admin', 'user']\n};\n\n// Utility function for deep merge\nfunction deepMerge\u003CT extends object, U extends object>(\n  target: T,\n  source: U\n): Merge\u003CT, U> {\n  const result: any = { ...target };\n  \n  for (const key in source) {\n    if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {\n      result[key] = deepMerge(result[key] || {}, source[key]);\n    } else {\n      result[key] = source[key];\n    }\n  }\n  \n  return result;\n}\n\n// Example usage\nconst baseConfig = {\n  api: { baseUrl: 'https://api.example.com', timeout: 5000 },\n  features: { analytics: true, notifications: false }\n};\n\nconst override = {\n  api: { timeout: 10000 },\n  features: { notifications: true }\n};\n\nconst merged = deepMerge(baseConfig, override);",{"id":506,"category":480,"title":507,"description":508,"author":9,"date":10,"tags":509,"code":512,"canPreview":488},"ts-event-emitter","Type Safe Event Emitter","Generic event emitter with type-safe event handling",[484,510,511],"Event Driven","Patterns","type EventMap = Record\u003Cstring, any>;\ntype EventKey\u003CT extends EventMap> = string & keyof T;\ntype EventCallback\u003CT> = (data: T) => void;\n\nclass TypedEventEmitter\u003CT extends EventMap> {\n  private listeners: {\n    [K in keyof T]?: EventCallback\u003CT[K]>[];\n  } = {};\n\n  // Subscribe to an event\n  on\u003CK extends EventKey\u003CT>>(\n    eventName: K,\n    callback: EventCallback\u003CT[K]>\n  ): () => void {\n    if (!this.listeners[eventName]) {\n      this.listeners[eventName] = [];\n    }\n    this.listeners[eventName]!.push(callback);\n\n    // Return unsubscribe function\n    return () => this.off(eventName, callback);\n  }\n\n  // Subscribe once\n  once\u003CK extends EventKey\u003CT>>(\n    eventName: K,\n    callback: EventCallback\u003CT[K]>\n  ): () => void {\n    const onceCallback: EventCallback\u003CT[K]> = (data) => {\n      callback(data);\n      this.off(eventName, onceCallback);\n    };\n    return this.on(eventName, onceCallback);\n  }\n\n  // Unsubscribe\n  off\u003CK extends EventKey\u003CT>>(\n    eventName: K,\n    callback: EventCallback\u003CT[K]>\n  ): void {\n    const callbacks = this.listeners[eventName];\n    if (!callbacks) return;\n    \n    const index = callbacks.indexOf(callback);\n    if (index > -1) {\n      callbacks.splice(index, 1);\n    }\n  }\n\n  // Emit event\n  emit\u003CK extends EventKey\u003CT>>(eventName: K, data: T[K]): void {\n    const callbacks = this.listeners[eventName];\n    if (!callbacks) return;\n    \n    // Create a copy to avoid issues if callbacks are removed during iteration\n    callbacks.slice().forEach(callback => {\n      try {\n        callback(data);\n      } catch (error) {\n        console.error(`Error in event listener for ${eventName}:`, error);\n      }\n    });\n  }\n\n  // Remove all listeners for an event\n  removeAllListeners\u003CK extends EventKey\u003CT>>(eventName?: K): void {\n    if (eventName) {\n      delete this.listeners[eventName];\n    } else {\n      this.listeners = {};\n    }\n  }\n\n  // Get listener count\n  listenerCount\u003CK extends EventKey\u003CT>>(eventName: K): number {\n    return this.listeners[eventName]?.length || 0;\n  }\n}\n\n// Usage examples\ninterface AppEvents {\n  'user:login': { userId: string; timestamp: Date };\n  'user:logout': { userId: string; reason: string };\n  'data:update': { data: any; version: number };\n  'error': Error;\n  'notification': { title: string; message: string; type: 'info' | 'warning' | 'error' };\n}\n\nconst emitter = new TypedEventEmitter\u003CAppEvents>();\n\n// Type-safe subscription\nconst unsubscribe = emitter.on('user:login', (data) => {\n  console.log(`User ${data.userId} logged in at ${data.timestamp}`);\n});\n\n// One-time listener\nemitter.once('notification', (notification) => {\n  console.log(`Notification: ${notification.title}`);\n});\n\n// Emit with type safety\nemitter.emit('user:login', { \n  userId: '123', \n  timestamp: new Date() \n});\n\nemitter.emit('error', new Error('Something went wrong'));\n\n// Clean up\nunsubscribe();\n\n// Advanced usage with async handlers\nclass AsyncEventEmitter\u003CT extends EventMap> extends TypedEventEmitter\u003CT> {\n  async emitAsync\u003CK extends EventKey\u003CT>>(eventName: K, data: T[K]): Promise\u003Cvoid> {\n    const callbacks = this.listeners[eventName];\n    if (!callbacks) return;\n    \n    const promises = callbacks.slice().map(callback => \n      Promise.resolve().then(() => callback(data))\n    );\n    \n    await Promise.all(promises);\n  }\n}",{"id":514,"category":480,"title":515,"description":516,"author":9,"date":10,"tags":517,"code":519,"canPreview":488},"ts-cache-manager","Cache Manager with TTL","Generic cache manager with time-to-live and size limits",[484,518,486],"Cache","interface CacheOptions\u003CK, V> {\n  ttl?: number; // Time to live in milliseconds\n  maxSize?: number;\n  onEviction?: (key: K, value: V) => void;\n}\n\ninterface CacheEntry\u003CV> {\n  value: V;\n  expiresAt: number;\n  lastAccessed: number;\n}\n\nclass CacheManager\u003CK, V> {\n  private cache = new Map\u003CK, CacheEntry\u003CV>>();\n  private ttl: number;\n  private maxSize: number;\n  private onEviction?: (key: K, value: V) => void;\n  private cleanupInterval: NodeJS.Timeout;\n\n  constructor(options: CacheOptions\u003CK, V> = {}) {\n    this.ttl = options.ttl || 60 * 1000; // Default 1 minute\n    this.maxSize = options.maxSize || 100;\n    this.onEviction = options.onEviction;\n    \n    // Auto cleanup every minute\n    this.cleanupInterval = setInterval(() => this.cleanup(), 60 * 1000);\n  }\n\n  set(key: K, value: V, customTTL?: number): void {\n    const now = Date.now();\n    const ttl = customTTL || this.ttl;\n    \n    // If cache is full, remove oldest item\n    if (this.cache.size >= this.maxSize && !this.cache.has(key)) {\n      this.evictOldest();\n    }\n    \n    this.cache.set(key, {\n      value,\n      expiresAt: now + ttl,\n      lastAccessed: now\n    });\n  }\n\n  get(key: K): V | undefined {\n    const entry = this.cache.get(key);\n    \n    if (!entry) return undefined;\n    \n    const now = Date.now();\n    \n    // Check if expired\n    if (entry.expiresAt \u003C= now) {\n      this.delete(key);\n      return undefined;\n    }\n    \n    // Update last accessed time\n    entry.lastAccessed = now;\n    \n    return entry.value;\n  }\n\n  has(key: K): boolean {\n    return this.get(key) !== undefined;\n  }\n\n  delete(key: K): boolean {\n    const entry = this.cache.get(key);\n    if (entry && this.onEviction) {\n      this.onEviction(key, entry.value);\n    }\n    return this.cache.delete(key);\n  }\n\n  clear(): void {\n    if (this.onEviction) {\n      this.cache.forEach((entry, key) => {\n        this.onEviction(key, entry.value);\n      });\n    }\n    this.cache.clear();\n  }\n\n  size(): number {\n    return this.cache.size;\n  }\n\n  keys(): K[] {\n    return Array.from(this.cache.keys());\n  }\n\n  values(): V[] {\n    return Array.from(this.cache.values()).map(entry => entry.value);\n  }\n\n  entries(): [K, V][] {\n    return Array.from(this.cache.entries()).map(([key, entry]) => [key, entry.value]);\n  }\n\n  private evictOldest(): void {\n    let oldestKey: K | null = null;\n    let oldestAccess = Infinity;\n    \n    for (const [key, entry] of this.cache.entries()) {\n      if (entry.lastAccessed \u003C oldestAccess) {\n        oldestAccess = entry.lastAccessed;\n        oldestKey = key;\n      }\n    }\n    \n    if (oldestKey) {\n      this.delete(oldestKey);\n    }\n  }\n\n  private cleanup(): void {\n    const now = Date.now();\n    \n    for (const [key, entry] of this.cache.entries()) {\n      if (entry.expiresAt \u003C= now) {\n        this.delete(key);\n      }\n    }\n  }\n\n  // Update TTL for a key\n  touch(key: K, newTTL?: number): boolean {\n    const entry = this.cache.get(key);\n    if (!entry) return false;\n    \n    const ttl = newTTL || this.ttl;\n    entry.expiresAt = Date.now() + ttl;\n    entry.lastAccessed = Date.now();\n    \n    return true;\n  }\n\n  // Get remaining TTL\n  getRemainingTTL(key: K): number | undefined {\n    const entry = this.cache.get(key);\n    if (!entry) return undefined;\n    \n    const remaining = entry.expiresAt - Date.now();\n    return remaining > 0 ? remaining : 0;\n  }\n\n  // Async version with automatic value fetching\n  async getOrSet(\n    key: K,\n    fetcher: () => Promise\u003CV>,\n    customTTL?: number\n  ): Promise\u003CV> {\n    const cached = this.get(key);\n    if (cached !== undefined) {\n      return cached;\n    }\n    \n    const value = await fetcher();\n    this.set(key, value, customTTL);\n    return value;\n  }\n\n  dispose(): void {\n    clearInterval(this.cleanupInterval);\n    this.clear();\n  }\n}\n\n// Usage examples\nconst cache = new CacheManager\u003Cstring, number>({\n  ttl: 5000,\n  maxSize: 50,\n  onEviction: (key, value) => {\n    console.log(`Evicted ${key}: ${value}`);\n  }\n});\n\n// Basic operations\ncache.set('result', 42);\nconst value = cache.get('result');\n\n// Async fetch\nconst fetchUserData = async (userId: string): Promise\u003Cany> => {\n  // Simulate API call\n  return { id: userId, name: 'John' };\n};\n\nconst userCache = new CacheManager\u003Cstring, any>({ ttl: 30000 });\n\nasync function getUser(userId: string) {\n  return userCache.getOrSet(\n    `user:${userId}`,\n    () => fetchUserData(userId)\n  );\n}",{"id":521,"category":480,"title":522,"description":523,"author":9,"date":10,"tags":524,"code":527,"canPreview":488},"ts-result-type","Result Type Pattern","Type-safe error handling with Result type",[484,525,526],"Error Handling","Functional","// Base Result type\ntype Result\u003CT, E = Error> = Success\u003CT> | Failure\u003CE>;\n\nclass Success\u003CT> {\n  readonly success = true;\n  constructor(readonly value: T) {}\n  \n  map\u003CU>(fn: (value: T) => U): Success\u003CU> {\n    return new Success(fn(this.value));\n  }\n  \n  flatMap\u003CU, E>(fn: (value: T) => Result\u003CU, E>): Result\u003CU, E> {\n    return fn(this.value);\n  }\n  \n  unwrap(): T {\n    return this.value;\n  }\n  \n  unwrapOr(_default: T): T {\n    return this.value;\n  }\n}\n\nclass Failure\u003CE> {\n  readonly success = false;\n  constructor(readonly error: E) {}\n  \n  map\u003CU>(_fn: (value: any) => U): Failure\u003CE> {\n    return this;\n  }\n  \n  flatMap\u003CU, F>(_fn: (value: any) => Result\u003CU, F>): Failure\u003CE> {\n    return this;\n  }\n  \n  unwrap(): never {\n    throw this.error;\n  }\n  \n  unwrapOr\u003CT>(defaultValue: T): T {\n    return defaultValue;\n  }\n}\n\n// Helper functions\nfunction success\u003CT>(value: T): Success\u003CT> {\n  return new Success(value);\n}\n\nfunction failure\u003CE>(error: E): Failure\u003CE> {\n  return new Failure(error);\n}\n\n// Try-catch wrapper\nfunction tryCatch\u003CT, E = Error>(\n  fn: () => T,\n  errorHandler?: (error: unknown) => E\n): Result\u003CT, E> {\n  try {\n    return success(fn());\n  } catch (error) {\n    return failure(errorHandler ? errorHandler(error) : error as E);\n  }\n}\n\n// Async version\nasync function tryCatchAsync\u003CT, E = Error>(\n  fn: () => Promise\u003CT>,\n  errorHandler?: (error: unknown) => E\n): Promise\u003CResult\u003CT, E>> {\n  try {\n    return success(await fn());\n  } catch (error) {\n    return failure(errorHandler ? errorHandler(error) : error as E);\n  }\n}\n\n// Combine multiple results\nfunction combine\u003CT1, T2, E>(r1: Result\u003CT1, E>, r2: Result\u003CT2, E>): Result\u003C[T1, T2], E>;\nfunction combine\u003CT1, T2, T3, E>(r1: Result\u003CT1, E>, r2: Result\u003CT2, E>, r3: Result\u003CT3, E>): Result\u003C[T1, T2, T3], E>;\nfunction combine\u003CE>(...results: Result\u003Cany, E>[]): Result\u003Cany[], E> {\n  const values: any[] = [];\n  \n  for (const result of results) {\n    if (!result.success) {\n      return result as Failure\u003CE>;\n    }\n    values.push(result.value);\n  }\n  \n  return success(values);\n}\n\n// Usage examples\n// Basic usage\nfunction divide(a: number, b: number): Result\u003Cnumber, string> {\n  if (b === 0) {\n    return failure('Division by zero');\n  }\n  return success(a / b);\n}\n\nconst result1 = divide(10, 2);\nif (result1.success) {\n  console.log('Result:', result1.value); // 5\n}\n\n// Chaining operations\nconst complexResult = divide(10, 2)\n  .map(x => x * 3)\n  .flatMap(x => divide(x, 5));\n\n// Error handling\nfunction parseJSONSafe\u003CT>(json: string): Result\u003CT, string> {\n  return tryCatch(\n    () => JSON.parse(json),\n    (error) => `JSON parse error: ${error}`\n  );\n}\n\n// Async example\nasync function fetchUser(id: number): Promise\u003CResult\u003CUser, string>> {\n  return tryCatchAsync(\n    async () => {\n      const response = await fetch(`/api/users/${id}`);\n      if (!response.ok) throw new Error('Network error');\n      return response.json();\n    },\n    (error) => `Failed to fetch user: ${error}`\n  );\n}\n\n// Railway-oriented programming\nclass UserService {\n  validateInput(input: any): Result\u003CUserInput, string> {\n    // validation logic\n    return success(input);\n  }\n  \n  async processUser(input: UserInput): Promise\u003CResult\u003CUser, string>> {\n    // processing logic\n    return success({ id: 1, name: 'John' });\n  }\n  \n  async createUser(rawInput: any): Promise\u003CResult\u003CUser, string>> {\n    return this.validateInput(rawInput)\n      .flatMap(input => this.processUser(input));\n  }\n}",{"id":529,"category":480,"title":530,"description":531,"author":9,"date":10,"tags":532,"code":535,"canPreview":488},"ts-builder-pattern","Builder Pattern with Fluent API","Type-safe builder pattern for complex object creation",[484,533,534],"Design Patterns","Builder","// Base Builder interface\ntype Builder\u003CT> = {\n  [K in keyof T]-?: (value: T[K]) => Builder\u003CT>;\n} & {\n  build(): T;\n};\n\n// Generic builder creator\nfunction createBuilder\u003CT>(): Builder\u003CT> {\n  const built: Partial\u003CT> = {};\n  \n  const handler: ProxyHandler\u003Cobject> = {\n    get(target, prop: string) {\n      if (prop === 'build') {\n        return () => {\n          // Validate required fields here if needed\n          return built as T;\n        };\n      }\n      \n      return (value: any) => {\n        built[prop as keyof T] = value;\n        return proxy;\n      };\n    }\n  };\n  \n  const proxy = new Proxy({}, handler);\n  return proxy as Builder\u003CT>;\n}\n\n// Example: User builder\ninterface User {\n  id: number;\n  name: string;\n  email: string;\n  age?: number;\n  roles: string[];\n  metadata: Record\u003Cstring, any>;\n}\n\n// Specific builder with validation\nclass UserBuilder {\n  private user: Partial\u003CUser> = {\n    roles: [],\n    metadata: {},\n  };\n  \n  withId(id: number): this {\n    this.user.id = id;\n    return this;\n  }\n  \n  withName(name: string): this {\n    if (name.length \u003C 2) {\n      throw new Error('Name must be at least 2 characters');\n    }\n    this.user.name = name;\n    return this;\n  }\n  \n  withEmail(email: string): this {\n    const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n    if (!emailRegex.test(email)) {\n      throw new Error('Invalid email address');\n    }\n    this.user.email = email;\n    return this;\n  }\n  \n  withAge(age: number): this {\n    if (age \u003C 0 || age > 150) {\n      throw new Error('Age must be between 0 and 150');\n    }\n    this.user.age = age;\n    return this;\n  }\n  \n  addRole(role: string): this {\n    this.user.roles!.push(role);\n    return this;\n  }\n  \n  withMetadata(key: string, value: any): this {\n    this.user.metadata![key] = value;\n    return this;\n  }\n  \n  build(): User {\n    // Validate required fields\n    if (!this.user.id || !this.user.name || !this.user.email) {\n      throw new Error('Missing required fields');\n    }\n    \n    return this.user as User;\n  }\n}\n\n// Advanced: Step builder pattern\ninterface QueryBuilder {\n  select(...columns: string[]): QueryBuilder;\n  from(table: string): QueryBuilder;\n  where(condition: string): QueryBuilder;\n  orderBy(column: string, direction?: 'ASC' | 'DESC'): QueryBuilder;\n  limit(count: number): QueryBuilder;\n  build(): string;\n}\n\nclass SQLQueryBuilder implements QueryBuilder {\n  private query = {\n    select: [] as string[],\n    from: '',\n    where: [] as string[],\n    orderBy: [] as string[],\n    limit: null as number | null,\n  };\n  \n  select(...columns: string[]): this {\n    this.query.select = columns;\n    return this;\n  }\n  \n  from(table: string): this {\n    this.query.from = table;\n    return this;\n  }\n  \n  where(condition: string): this {\n    this.query.where.push(condition);\n    return this;\n  }\n  \n  andWhere(condition: string): this {\n    this.query.where.push(`AND ${condition}`);\n    return this;\n  }\n  \n  orWhere(condition: string): this {\n    this.query.where.push(`OR ${condition}`);\n    return this;\n  }\n  \n  orderBy(column: string, direction: 'ASC' | 'DESC' = 'ASC'): this {\n    this.query.orderBy.push(`${column} ${direction}`);\n    return this;\n  }\n  \n  limit(count: number): this {\n    this.query.limit = count;\n    return this;\n  }\n  \n  build(): string {\n    if (!this.query.select.length || !this.query.from) {\n      throw new Error('SELECT and FROM clauses are required');\n    }\n    \n    const parts = [\n      `SELECT ${this.query.select.join(', ')}`,\n      `FROM ${this.query.from}`,\n    ];\n    \n    if (this.query.where.length) {\n      parts.push(`WHERE ${this.query.where.join(' ')}`);\n    }\n    \n    if (this.query.orderBy.length) {\n      parts.push(`ORDER BY ${this.query.orderBy.join(', ')}`);\n    }\n    \n    if (this.query.limit !== null) {\n      parts.push(`LIMIT ${this.query.limit}`);\n    }\n    \n    return parts.join('\\n');\n  }\n}\n\n// Usage examples\n// Generic builder\nconst user = createBuilder\u003CUser>()\n  .id(1)\n  .name('John Doe')\n  .email('john@example.com')\n  .age(30)\n  .build();\n\n// Specific builder with validation\nconst user2 = new UserBuilder()\n  .withId(1)\n  .withName('Jane Smith')\n  .withEmail('jane@example.com')\n  .addRole('admin')\n  .addRole('user')\n  .withMetadata('createdAt', new Date())\n  .build();\n\n// Query builder\nconst query = new SQLQueryBuilder()\n  .select('id', 'name', 'email')\n  .from('users')\n  .where('age > 18')\n  .andWhere('status = \"active\"')\n  .orderBy('name', 'ASC')\n  .limit(10)\n  .build();",{"id":537,"category":480,"title":538,"description":539,"author":9,"date":10,"tags":540,"code":543,"canPreview":488},"ts-observable-pattern","Observable Pattern","Simple Observable implementation with operators",[484,541,542],"Reactive","Observable","type Observer\u003CT> = {\n  next: (value: T) => void;\n  error?: (error: any) => void;\n  complete?: () => void;\n};\n\ntype Unsubscribe = () => void;\n\ntype Operator\u003CT, R> = (source: Observable\u003CT>) => Observable\u003CR>;\n\nclass Observable\u003CT> {\n  private subscribers: Observer\u003CT>[] = [];\n  private isCompleted = false;\n  \n  constructor(private executor: (observer: Observer\u003CT>) => Unsubscribe | void) {}\n  \n  // Subscribe to observable\n  subscribe(observer: Observer\u003CT> | ((value: T) => void)): Unsubscribe {\n    const normalizedObserver: Observer\u003CT> = \n      typeof observer === 'function' \n        ? { next: observer }\n        : observer;\n    \n    this.subscribers.push(normalizedObserver);\n    \n    // Execute the observable\n    const unsubscribe = this.executor({\n      next: (value) => {\n        if (this.isCompleted) return;\n        normalizedObserver.next(value);\n      },\n      error: (error) => {\n        if (this.isCompleted) return;\n        normalizedObserver.error?.(error);\n        this.complete();\n      },\n      complete: () => {\n        if (this.isCompleted) return;\n        normalizedObserver.complete?.();\n        this.complete();\n      }\n    });\n    \n    return () => {\n      const index = this.subscribers.indexOf(normalizedObserver);\n      if (index > -1) {\n        this.subscribers.splice(index, 1);\n      }\n      if (typeof unsubscribe === 'function') {\n        unsubscribe();\n      }\n    };\n  }\n  \n  // Pipe operators\n  pipe\u003CR>(operator: Operator\u003CT, R>): Observable\u003CR> {\n    return operator(this);\n  }\n  \n  // Helper method to emit values\n  private emit(value: T): void {\n    if (this.isCompleted) return;\n    this.subscribers.forEach(subscriber => subscriber.next(value));\n  }\n  \n  private error(err: any): void {\n    if (this.isCompleted) return;\n    this.subscribers.forEach(subscriber => subscriber.error?.(err));\n    this.complete();\n  }\n  \n  private complete(): void {\n    if (this.isCompleted) return;\n    this.isCompleted = true;\n    this.subscribers.forEach(subscriber => subscriber.complete?.());\n    this.subscribers = [];\n  }\n  \n  // Static creation methods\n  static of\u003CT>(...values: T[]): Observable\u003CT> {\n    return new Observable(observer => {\n      values.forEach(value => observer.next(value));\n      observer.complete?.();\n    });\n  }\n  \n  static from\u003CT>(iterable: Iterable\u003CT> | ArrayLike\u003CT>): Observable\u003CT> {\n    return new Observable(observer => {\n      try {\n        for (const value of iterable as any) {\n          observer.next(value);\n        }\n        observer.complete?.();\n      } catch (error) {\n        observer.error?.(error);\n      }\n    });\n  }\n  \n  static interval(period: number): Observable\u003Cnumber> {\n    return new Observable(observer => {\n      let count = 0;\n      const intervalId = setInterval(() => {\n        observer.next(count++);\n      }, period);\n      \n      return () => clearInterval(intervalId);\n    });\n  }\n  \n  static fromEvent\u003CT extends Event>(element: EventTarget, eventName: string): Observable\u003CT> {\n    return new Observable(observer => {\n      const handler = (event: Event) => observer.next(event as T);\n      element.addEventListener(eventName, handler);\n      \n      return () => element.removeEventListener(eventName, handler);\n    });\n  }\n}\n\n// Operators\nfunction map\u003CT, R>(transform: (value: T) => R): Operator\u003CT, R> {\n  return (source: Observable\u003CT>) => \n    new Observable\u003CR>(observer => {\n      return source.subscribe({\n        next: value => observer.next(transform(value)),\n        error: err => observer.error?.(err),\n        complete: () => observer.complete?.()\n      });\n    });\n}\n\nfunction filter\u003CT>(predicate: (value: T) => boolean): Operator\u003CT, T> {\n  return (source: Observable\u003CT>) => \n    new Observable\u003CT>(observer => {\n      return source.subscribe({\n        next: value => {\n          if (predicate(value)) {\n            observer.next(value);\n          }\n        },\n        error: err => observer.error?.(err),\n        complete: () => observer.complete?.()\n      });\n    });\n}\n\nfunction debounceTime\u003CT>(delay: number): Operator\u003CT, T> {\n  return (source: Observable\u003CT>) => \n    new Observable\u003CT>(observer => {\n      let timeoutId: NodeJS.Timeout;\n      \n      const subscription = source.subscribe({\n        next: value => {\n          clearTimeout(timeoutId);\n          timeoutId = setTimeout(() => observer.next(value), delay);\n        },\n        error: err => observer.error?.(err),\n        complete: () => {\n          clearTimeout(timeoutId);\n          observer.complete?.();\n        }\n      });\n      \n      return () => {\n        clearTimeout(timeoutId);\n        subscription();\n      };\n    });\n}\n\nfunction take\u003CT>(count: number): Operator\u003CT, T> {\n  return (source: Observable\u003CT>) => \n    new Observable\u003CT>(observer => {\n      let taken = 0;\n      \n      const subscription = source.subscribe({\n        next: value => {\n          if (taken++ \u003C count) {\n            observer.next(value);\n            if (taken === count) {\n              observer.complete?.();\n              subscription();\n            }\n          }\n        },\n        error: err => observer.error?.(err),\n        complete: () => observer.complete?.()\n      });\n      \n      return subscription;\n    });\n}\n\n// Usage examples\n// Create observables\nconst numbers$ = Observable.of(1, 2, 3, 4, 5);\nconst interval$ = Observable.interval(1000);\n\n// Subscribe\nconst unsubscribe = numbers$.subscribe({\n  next: value => console.log('Number:', value),\n  complete: () => console.log('Complete!')\n});\n\n// Using operators\nconst processed$ = numbers$.pipe(\n  filter(x => x % 2 === 0),\n  map(x => x * 10),\n  take(2)\n);\n\nprocessed$.subscribe(value => console.log('Processed:', value));\n\n// From DOM events\nconst button = document.querySelector('button');\nif (button) {\n  const clicks$ = Observable.fromEvent\u003CMouseEvent>(button, 'click');\n  \n  clicks$\n    .pipe(\n      debounceTime(300),\n      map(event => ({ x: event.clientX, y: event.clientY }))\n    )\n    .subscribe(coords => {\n      console.log('Clicked at:', coords);\n    });\n}\n\n// Custom observable\nconst custom$ = new Observable\u003Cnumber>(observer => {\n  let count = 0;\n  const interval = setInterval(() => {\n    observer.next(count++);\n    if (count === 5) {\n      observer.complete?.();\n    }\n  }, 500);\n  \n  return () => clearInterval(interval);\n});",{"id":545,"category":480,"title":546,"description":547,"author":9,"date":10,"tags":548,"code":550,"canPreview":488},"ts-retry-mechanism","Retry Mechanism with Exponential Backoff","Configurable retry utility for async operations with backoff strategies",[484,549,525],"Async","interface RetryOptions\u003CT> {\n  maxAttempts?: number;\n  delay?: number;\n  maxDelay?: number;\n  factor?: number;\n  jitter?: boolean;\n  shouldRetry?: (error: any, attempt: number) => boolean;\n  onRetry?: (error: any, attempt: number, delay: number) => void;\n  timeout?: number;\n}\n\ntype RetryResult\u003CT> = {\n  success: true;\n  value: T;\n  attempts: number;\n  duration: number;\n} | {\n  success: false;\n  error: any;\n  attempts: number;\n  duration: number;\n};\n\nclass RetryManager {\n  static async execute\u003CT>(\n    fn: () => Promise\u003CT>,\n    options: RetryOptions\u003CT> = {}\n  ): Promise\u003CRetryResult\u003CT>> {\n    const {\n      maxAttempts = 3,\n      delay = 1000,\n      maxDelay = 30000,\n      factor = 2,\n      jitter = true,\n      shouldRetry = () => true,\n      onRetry,\n      timeout\n    } = options;\n    \n    const startTime = Date.now();\n    let lastError: any;\n    \n    for (let attempt = 1; attempt \u003C= maxAttempts; attempt++) {\n      try {\n        let promise = fn();\n        \n        // Add timeout if specified\n        if (timeout) {\n          promise = Promise.race([\n            promise,\n            new Promise\u003Cnever>((_, reject) => \n              setTimeout(() => reject(new Error('Operation timeout')), timeout)\n            )\n          ]);\n        }\n        \n        const value = await promise;\n        const duration = Date.now() - startTime;\n        \n        return {\n          success: true,\n          value,\n          attempts: attempt,\n          duration\n        };\n      } catch (error) {\n        lastError = error;\n        \n        // Check if we should retry\n        if (attempt === maxAttempts || !shouldRetry(error, attempt)) {\n          const duration = Date.now() - startTime;\n          return {\n            success: false,\n            error,\n            attempts: attempt,\n            duration\n          };\n        }\n        \n        // Calculate delay with exponential backoff\n        const baseDelay = delay * Math.pow(factor, attempt - 1);\n        const cappedDelay = Math.min(baseDelay, maxDelay);\n        \n        // Add jitter if enabled\n        const actualDelay = jitter \n          ? cappedDelay * (0.5 + Math.random() * 0.5)\n          : cappedDelay;\n        \n        // Call onRetry callback\n        onRetry?.(error, attempt, actualDelay);\n        \n        // Wait before retrying\n        if (actualDelay > 0) {\n          await new Promise(resolve => setTimeout(resolve, actualDelay));\n        }\n      }\n    }\n    \n    const duration = Date.now() - startTime;\n    return {\n      success: false,\n      error: lastError,\n      attempts: maxAttempts,\n      duration\n    };\n  }\n  \n  // Factory method for creating retryable functions\n  static create\u003CT>(\n    fn: () => Promise\u003CT>,\n    options: RetryOptions\u003CT> = {}\n  ): () => Promise\u003CT> {\n    return async () => {\n      const result = await RetryManager.execute(fn, options);\n      if (!result.success) {\n        throw result.error;\n      }\n      return result.value;\n    };\n  }\n  \n  // Circuit breaker pattern\n  static withCircuitBreaker\u003CT>(\n    fn: () => Promise\u003CT>,\n    options: {\n      failureThreshold: number;\n      resetTimeout: number;\n      retryOptions?: RetryOptions\u003CT>;\n    }\n  ): () => Promise\u003CT> {\n    let state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';\n    let failureCount = 0;\n    let lastFailureTime = 0;\n    \n    return async () => {\n      const now = Date.now();\n      \n      // Check if circuit breaker is open\n      if (state === 'OPEN') {\n        if (now - lastFailureTime >= options.resetTimeout) {\n          state = 'HALF_OPEN';\n        } else {\n          throw new Error('Circuit breaker is open');\n        }\n      }\n      \n      try {\n        const result = await RetryManager.execute(fn, options.retryOptions);\n        \n        if (result.success) {\n          // Reset on success\n          if (state === 'HALF_OPEN') {\n            state = 'CLOSED';\n            failureCount = 0;\n          }\n          return result.value;\n        } else {\n          throw result.error;\n        }\n      } catch (error) {\n        failureCount++;\n        lastFailureTime = now;\n        \n        if (state === 'HALF_OPEN' || failureCount >= options.failureThreshold) {\n          state = 'OPEN';\n        }\n        \n        throw error;\n      }\n    };\n  }\n}\n\n// Utility functions for common retry strategies\nconst retryStrategies = {\n  exponential: (options?: Partial\u003CRetryOptions\u003Cany>>) => ({\n    maxAttempts: 5,\n    delay: 1000,\n    factor: 2,\n    jitter: true,\n    ...options\n  }),\n  \n  fixed: (options?: Partial\u003CRetryOptions\u003Cany>>) => ({\n    maxAttempts: 3,\n    delay: 2000,\n    factor: 1,\n    jitter: false,\n    ...options\n  }),\n  \n  immediate: (options?: Partial\u003CRetryOptions\u003Cany>>) => ({\n    maxAttempts: 3,\n    delay: 0,\n    ...options\n  }),\n  \n  network: (options?: Partial\u003CRetryOptions\u003Cany>>) => ({\n    maxAttempts: 3,\n    delay: 1000,\n    factor: 2,\n    maxDelay: 10000,\n    shouldRetry: (error: any) => \n      error.code === 'ETIMEDOUT' || \n      error.code === 'ECONNREFUSED' ||\n      error.message?.includes('network'),\n    ...options\n  })\n};\n\n// Usage examples\nasync function fetchWithRetry(url: string) {\n  return RetryManager.execute(\n    async () => {\n      const response = await fetch(url);\n      if (!response.ok) {\n        throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n      }\n      return response.json();\n    },\n    retryStrategies.network({\n      maxAttempts: 5,\n      onRetry: (error, attempt, delay) => {\n        console.log(`Retry ${attempt} after ${delay}ms: ${error.message}`);\n      }\n    })\n  );\n}\n\n// Create retryable API client\nconst apiClient = {\n  get: RetryManager.create(\n    async (endpoint: string) => {\n      const response = await fetch(`/api/${endpoint}`);\n      return response.json();\n    },\n    retryStrategies.exponential()\n  ),\n  \n  post: RetryManager.create(\n    async (endpoint: string, data: any) => {\n      const response = await fetch(`/api/${endpoint}`, {\n        method: 'POST',\n        body: JSON.stringify(data)\n      });\n      return response.json();\n    },\n    retryStrategies.fixed()\n  )\n};\n\n// With circuit breaker\nconst resilientApiCall = RetryManager.withCircuitBreaker(\n  async () => {\n    const response = await fetch('/api/sensitive');\n    return response.json();\n  },\n  {\n    failureThreshold: 5,\n    resetTimeout: 60000,\n    retryOptions: retryStrategies.exponential()\n  }\n);",{"id":552,"category":480,"title":553,"description":554,"author":9,"date":10,"tags":555,"code":557,"canPreview":488},"ts-state-machine","Finite State Machine","Type-safe finite state machine implementation",[484,556,511],"State Machine","type Transition\u003CState extends string, Event extends string> = [State, Event, State];\n\ninterface StateMachineConfig\u003C\n  State extends string,\n  Event extends string,\n  Context = any\n> {\n  initialState: State;\n  initialContext: Context;\n  states: Record\u003CState, {\n    onEntry?: (context: Context) => Context | void;\n    onExit?: (context: Context) => Context | void;\n  }>;\n  transitions: Transition\u003CState, Event>[];\n  onTransition?: (from: State, to: State, event: Event, context: Context) => void;\n}\n\nclass StateMachine\u003C\n  State extends string,\n  Event extends string,\n  Context = any\n> {\n  private currentState: State;\n  private context: Context;\n  private transitions: Map\u003CState, Map\u003CEvent, State>> = new Map();\n  \n  constructor(private config: StateMachineConfig\u003CState, Event, Context>) {\n    this.currentState = config.initialState;\n    this.context = config.initialContext;\n    this.initializeTransitions();\n    \n    // Call initial state entry\n    this.callEntry(this.currentState);\n  }\n  \n  private initializeTransitions(): void {\n    for (const [from, event, to] of this.config.transitions) {\n      if (!this.transitions.has(from)) {\n        this.transitions.set(from, new Map());\n      }\n      this.transitions.get(from)!.set(event, to);\n    }\n  }\n  \n  private callEntry(state: State): void {\n    const stateConfig = this.config.states[state];\n    if (stateConfig?.onEntry) {\n      const result = stateConfig.onEntry(this.context);\n      if (result !== undefined) {\n        this.context = result;\n      }\n    }\n  }\n  \n  private callExit(state: State): void {\n    const stateConfig = this.config.states[state];\n    if (stateConfig?.onExit) {\n      const result = stateConfig.onExit(this.context);\n      if (result !== undefined) {\n        this.context = result;\n      }\n    }\n  }\n  \n  get state(): State {\n    return this.currentState;\n  }\n  \n  get contextData(): Context {\n    return this.context;\n  }\n  \n  send(event: Event): boolean {\n    const stateTransitions = this.transitions.get(this.currentState);\n    if (!stateTransitions) return false;\n    \n    const nextState = stateTransitions.get(event);\n    if (!nextState) return false;\n    \n    // Exit current state\n    this.callExit(this.currentState);\n    \n    const previousState = this.currentState;\n    this.currentState = nextState;\n    \n    // Enter new state\n    this.callEntry(nextState);\n    \n    // Call transition callback\n    this.config.onTransition?.(previousState, nextState, event, this.context);\n    \n    return true;\n  }\n  \n  can(event: Event): boolean {\n    const stateTransitions = this.transitions.get(this.currentState);\n    return stateTransitions?.has(event) || false;\n  }\n  \n  allowedEvents(): Event[] {\n    const stateTransitions = this.transitions.get(this.currentState);\n    return stateTransitions ? Array.from(stateTransitions.keys()) : [];\n  }\n  \n  updateContext(updater: (context: Context) => Context): void {\n    this.context = updater(this.context);\n  }\n}\n\n// Example: Download state machine\ninterface DownloadContext {\n  progress: number;\n  fileSize?: number;\n  error?: string;\n  startTime?: Date;\n  endTime?: Date;\n}\n\ntype DownloadState = 'idle' | 'downloading' | 'paused' | 'completed' | 'error';\ntype DownloadEvent = 'start' | 'pause' | 'resume' | 'complete' | 'error' | 'reset';\n\nconst downloadMachine = new StateMachine\u003CDownloadState, DownloadEvent, DownloadContext>({\n  initialState: 'idle',\n  initialContext: { progress: 0 },\n  \n  states: {\n    idle: {\n      onEntry: (context) => ({ ...context, progress: 0, error: undefined })\n    },\n    downloading: {\n      onEntry: (context) => ({ ...context, startTime: new Date() }),\n      onExit: (context) => {\n        if (context.progress === 100) {\n          return { ...context, endTime: new Date() };\n        }\n        return context;\n      }\n    },\n    paused: {},\n    completed: {},\n    error: {\n      onEntry: (context) => ({ ...context, endTime: new Date() })\n    }\n  },\n  \n  transitions: [\n    ['idle', 'start', 'downloading'],\n    ['downloading', 'pause', 'paused'],\n    ['downloading', 'complete', 'completed'],\n    ['downloading', 'error', 'error'],\n    ['paused', 'resume', 'downloading'],\n    ['paused', 'error', 'error'],\n    ['completed', 'reset', 'idle'],\n    ['error', 'reset', 'idle']\n  ],\n  \n  onTransition: (from, to, event, context) => {\n    console.log(`${from} -> ${to} via ${event}`);\n  }\n});\n\n// Usage\nconsole.log('Initial state:', downloadMachine.state); // 'idle'\nconsole.log('Can start?', downloadMachine.can('start')); // true\n\ndownloadMachine.send('start');\nconsole.log('Current state:', downloadMachine.state); // 'downloading'\n\n// Update progress\nconst interval = setInterval(() => {\n  if (downloadMachine.state === 'downloading') {\n    downloadMachine.updateContext(ctx => ({\n      ...ctx,\n      progress: Math.min(ctx.progress + 10, 100)\n    }));\n    \n    if (downloadMachine.contextData.progress === 100) {\n      downloadMachine.send('complete');\n      clearInterval(interval);\n    }\n  }\n}, 1000);\n\n// Guarded transitions function\nfunction createGuardedStateMachine\u003C\n  State extends string,\n  Event extends string,\n  Context = any\n>(\n  config: StateMachineConfig\u003CState, Event, Context> & {\n    guards?: Partial\u003CRecord\u003CEvent, (context: Context) => boolean>>;\n  }\n) {\n  const baseMachine = new StateMachine\u003CState, Event, Context>(config);\n  \n  return {\n    ...baseMachine,\n    \n    send(event: Event): boolean {\n      const guard = config.guards?.[event];\n      if (guard && !guard(baseMachine.contextData)) {\n        return false;\n      }\n      return baseMachine.send(event);\n    }\n  };\n}\n\n// Async state machine with side effects\nclass AsyncStateMachine\u003C\n  State extends string,\n  Event extends string,\n  Context = any\n> extends StateMachine\u003CState, Event, Context> {\n  async sendAsync(\n    event: Event,\n    effect?: (context: Context) => Promise\u003CContext | void>\n  ): Promise\u003Cboolean> {\n    if (!this.can(event)) return false;\n    \n    if (effect) {\n      try {\n        const result = await effect(this.contextData);\n        if (result !== undefined) {\n          this.updateContext(() => result);\n        }\n      } catch (error) {\n        return false;\n      }\n    }\n    \n    return this.send(event);\n  }\n}",{"id":559,"category":480,"title":560,"description":561,"author":9,"date":10,"tags":562,"code":564,"canPreview":488},"ts-functional-utils","Functional Programming Utilities","Collection of functional programming utilities with TypeScript",[484,526,563],"Utilities","// Currying\nfunction curry\u003CT extends any[], R>(\n  fn: (...args: T) => R\n): (...args: T) => R {\n  const curried = (...args: any[]): any => {\n    if (args.length >= fn.length) {\n      return fn(...args as T);\n    }\n    return (...nextArgs: any[]) => curried(...args, ...nextArgs);\n  };\n  return curried as (...args: T) => R;\n}\n\n// Partial application\nfunction partial\u003CT extends any[], R>(\n  fn: (...args: T) => R,\n  ...partialArgs: any[]\n): (...args: any[]) => R {\n  return (...remainingArgs: any[]) => \n    fn(...partialArgs, ...remainingArgs) as R;\n}\n\n// Compose functions\nfunction compose\u003CT>(\n  ...fns: ((arg: any) => any)[]\n): (initialValue: T) => any {\n  return (initialValue: T) => \n    fns.reduceRight((value, fn) => fn(value), initialValue);\n}\n\n// Pipe functions (left to right composition)\nfunction pipe\u003CT>(\n  ...fns: ((arg: any) => any)[]\n): (initialValue: T) => any {\n  return (initialValue: T) => \n    fns.reduce((value, fn) => fn(value), initialValue);\n}\n\n// Memoization\nfunction memoize\u003CT extends (...args: any[]) => any>(\n  fn: T,\n  resolver?: (...args: Parameters\u003CT>) => string\n): T {\n  const cache = new Map\u003Cstring, ReturnType\u003CT>>();\n  \n  return ((...args: Parameters\u003CT>): ReturnType\u003CT> => {\n    const key = resolver ? resolver(...args) : JSON.stringify(args);\n    \n    if (cache.has(key)) {\n      return cache.get(key)!;\n    }\n    \n    const result = fn(...args);\n    cache.set(key, result);\n    return result;\n  }) as T;\n}\n\n// Tap (for side effects in pipelines)\nfunction tap\u003CT>(effect: (value: T) => void): (value: T) => T {\n  return (value: T) => {\n    effect(value);\n    return value;\n  };\n}\n\n// Maybe monad\nclass Maybe\u003CT> {\n  private constructor(private value: T | null) {}\n  \n  static just\u003CT>(value: T): Maybe\u003CT> {\n    return new Maybe(value);\n  }\n  \n  static nothing\u003CT>(): Maybe\u003CT> {\n    return new Maybe\u003CT>(null);\n  }\n  \n  static from\u003CT>(value: T | null | undefined): Maybe\u003CT> {\n    return value == null ? Maybe.nothing() : Maybe.just(value);\n  }\n  \n  map\u003CU>(fn: (value: T) => U): Maybe\u003CU> {\n    return this.value == null ? Maybe.nothing\u003CU>() : Maybe.just(fn(this.value));\n  }\n  \n  flatMap\u003CU>(fn: (value: T) => Maybe\u003CU>): Maybe\u003CU> {\n    return this.value == null ? Maybe.nothing\u003CU>() : fn(this.value);\n  }\n  \n  getOrElse(defaultValue: T): T {\n    return this.value == null ? defaultValue : this.value;\n  }\n  \n  isJust(): boolean {\n    return this.value != null;\n  }\n  \n  isNothing(): boolean {\n    return this.value == null;\n  }\n}\n\n// Either monad\ntype Either\u003CL, R> = Left\u003CL> | Right\u003CR>;\n\nclass Left\u003CL> {\n  readonly tag = 'Left' as const;\n  constructor(readonly value: L) {}\n  \n  map\u003CR>(_fn: (value: any) => R): Either\u003CL, R> {\n    return this;\n  }\n  \n  flatMap\u003CR>(_fn: (value: any) => Either\u003CL, R>): Either\u003CL, R> {\n    return this;\n  }\n}\n\nclass Right\u003CR> {\n  readonly tag = 'Right' as const;\n  constructor(readonly value: R) {}\n  \n  map\u003CS>(fn: (value: R) => S): Either\u003Cany, S> {\n    return new Right(fn(this.value));\n  }\n  \n  flatMap\u003CL, S>(fn: (value: R) => Either\u003CL, S>): Either\u003CL, S> {\n    return fn(this.value);\n  }\n}\n\n// Utility functions for Either\nconst left = \u003CL, R>(value: L): Either\u003CL, R> => new Left(value);\nconst right = \u003CL, R>(value: R): Either\u003CL, R> => new Right(value);\n\n// Lazy evaluation\nclass Lazy\u003CT> {\n  private fn: () => T;\n  private cachedValue?: T;\n  private evaluated = false;\n  \n  constructor(fn: () => T) {\n    this.fn = fn;\n  }\n  \n  static of\u003CT>(value: T): Lazy\u003CT> {\n    return new Lazy(() => value);\n  }\n  \n  map\u003CU>(fn: (value: T) => U): Lazy\u003CU> {\n    return new Lazy(() => fn(this.value));\n  }\n  \n  flatMap\u003CU>(fn: (value: T) => Lazy\u003CU>): Lazy\u003CU> {\n    return new Lazy(() => fn(this.value).value);\n  }\n  \n  get value(): T {\n    if (!this.evaluated) {\n      this.cachedValue = this.fn();\n      this.evaluated = true;\n    }\n    return this.cachedValue!;\n  }\n}\n\n// Higher-order functions\nfunction not\u003CT>(fn: (value: T) => boolean): (value: T) => boolean {\n  return (value: T) => !fn(value);\n}\n\nfunction and\u003CT>(...fns: ((value: T) => boolean)[]): (value: T) => boolean {\n  return (value: T) => fns.every(fn => fn(value));\n}\n\nfunction or\u003CT>(...fns: ((value: T) => boolean)[]): (value: T) => boolean {\n  return (value: T) => fns.some(fn => fn(value));\n}\n\n// Usage examples\n// Currying\nconst add = (a: number, b: number) => a + b;\nconst curriedAdd = curry(add);\nconst add5 = curriedAdd(5);\nconsole.log(add5(3)); // 8\n\n// Composition\nconst double = (x: number) => x * 2;\nconst square = (x: number) => x * x;\nconst doubleThenSquare = compose(square, double);\nconsole.log(doubleThenSquare(3)); // 36\n\nconst squareThenDouble = pipe(double, square);\nconsole.log(squareThenDouble(3)); // 36\n\n// Memoization\nconst expensiveCalculation = memoize((a: number, b: number) => {\n  console.log('Calculating...');\n  return a + b;\n});\nconsole.log(expensiveCalculation(1, 2)); // Calculating... 3\nconsole.log(expensiveCalculation(1, 2)); // 3 (cached)\n\n// Maybe monad\nconst getUser = (id: number): Maybe\u003C{ name: string; age: number }> => {\n  return id > 0 ? Maybe.just({ name: 'John', age: 30 }) : Maybe.nothing();\n};\n\nconst userName = getUser(1)\n  .map(user => user.name.toUpperCase())\n  .getOrElse('Unknown');\n\n// Either monad\nfunction divideEither(a: number, b: number): Either\u003Cstring, number> {\n  return b === 0 ? left('Division by zero') : right(a / b);\n}\n\nconst result = divideEither(10, 2)\n  .map(x => x * 3)\n  .flatMap(x => divideEither(x, 5));\n\n// Lazy evaluation\nconst lazyValue = Lazy.of(() => {\n  console.log('Computing...');\n  return 42;\n});\n\nconsole.log(lazyValue.value); // Computing... 42\nconsole.log(lazyValue.value); // 42 (cached)\n\n// Pipeline with tap\nconst processData = pipe(\n  (x: number) => x * 2,\n  tap(x => console.log('After doubling:', x)),\n  (x: number) => x + 10,\n  tap(x => console.log('After adding:', x))\n);\n\nconsole.log(processData(5)); // 20",{"id":566,"category":480,"title":567,"description":568,"author":9,"date":10,"tags":569,"code":572,"canPreview":488},"ts-dependency-injection","Lightweight Dependency Injection Container","Simple yet powerful DI container with lifecycle management and scopes",[484,570,571,533],"Dependency Injection","IoC","interface ServiceDescriptor\u003CT = any> {\n  token: string | symbol | Function;\n  factory: (...args: any[]) => T;\n  lifecycle: 'singleton' | 'transient' | 'scoped';\n  dependencies?: (string | symbol | Function)[];\n}\n\ntype ServiceToken\u003CT = any> = string | symbol | (new (...args: any[]) => T);\n\nclass DIContainer {\n  private descriptors = new Map\u003CServiceToken, ServiceDescriptor>();\n  private singletons = new Map\u003CServiceToken, any>();\n  private scopedInstances = new Map\u003CServiceToken, any>();\n  private currentScope: string | null = null;\n  \n  // Registration methods\n  register\u003CT>({\n    token,\n    factory,\n    lifecycle = 'transient',\n    dependencies = []\n  }: {\n    token: ServiceToken\u003CT>;\n    factory: (...args: any[]) => T;\n    lifecycle?: ServiceDescriptor['lifecycle'];\n    dependencies?: ServiceDescriptor['dependencies'];\n  }): this {\n    this.descriptors.set(token, {\n      token,\n      factory,\n      lifecycle,\n      dependencies\n    });\n    return this;\n  }\n  \n  registerClass\u003CT>(\n    token: ServiceToken\u003CT>,\n    implementation: new (...args: any[]) => T,\n    lifecycle: ServiceDescriptor['lifecycle'] = 'transient',\n    dependencies: ServiceDescriptor['dependencies'] = []\n  ): this {\n    return this.register({\n      token,\n      factory: (...args) => new implementation(...args),\n      lifecycle,\n      dependencies\n    });\n  }\n  \n  registerInstance\u003CT>(token: ServiceToken\u003CT>, instance: T): this {\n    this.descriptors.set(token, {\n      token,\n      factory: () => instance,\n      lifecycle: 'singleton',\n      dependencies: []\n    });\n    this.singletons.set(token, instance);\n    return this;\n  }\n  \n  // Resolution methods\n  resolve\u003CT>(token: ServiceToken\u003CT>): T {\n    const descriptor = this.descriptors.get(token);\n    if (!descriptor) {\n      throw new Error(`Service not registered: ${token.toString()}`);\n    }\n    \n    // Check lifecycle\n    switch (descriptor.lifecycle) {\n      case 'singleton':\n        if (!this.singletons.has(token)) {\n          this.singletons.set(token, this.createInstance(descriptor));\n        }\n        return this.singletons.get(token);\n        \n      case 'scoped':\n        if (!this.currentScope) {\n          throw new Error('Cannot resolve scoped service outside of a scope');\n        }\n        if (!this.scopedInstances.has(token)) {\n          this.scopedInstances.set(token, this.createInstance(descriptor));\n        }\n        return this.scopedInstances.get(token);\n        \n      case 'transient':\n        return this.createInstance(descriptor);\n    }\n  }\n  \n  private createInstance\u003CT>(descriptor: ServiceDescriptor\u003CT>): T {\n    const dependencies = descriptor.dependencies?.map(dep => {\n      // Check if dependency is a class constructor\n      if (typeof dep === 'function' && dep.prototype) {\n        return this.resolve(dep);\n      }\n      return this.resolve(dep as ServiceToken);\n    }) || [];\n    \n    return descriptor.factory(...dependencies);\n  }\n  \n  // Scopes\n  createScope(): { run\u003CT>(callback: () => T): T; dispose(): void } {\n    const scopeId = Symbol('scope');\n    const previousScope = this.currentScope;\n    const previousInstances = new Map(this.scopedInstances);\n    \n    return {\n      run: \u003CT>(callback: () => T): T => {\n        this.currentScope = scopeId.toString();\n        this.scopedInstances.clear();\n        \n        try {\n          return callback();\n        } finally {\n          this.currentScope = previousScope;\n          this.scopedInstances = previousInstances;\n        }\n      },\n      dispose: () => {\n        this.scopedInstances.clear();\n        if (this.currentScope === scopeId.toString()) {\n          this.currentScope = null;\n        }\n      }\n    };\n  }\n  \n  // Factory method for resolving with additional dependencies\n  factory\u003CT>(token: ServiceToken\u003CT>): (...additionalDeps: any[]) => T {\n    return (...additionalDeps) => {\n      const descriptor = this.descriptors.get(token);\n      if (!descriptor) {\n        throw new Error(`Service not registered: ${token.toString()}`);\n      }\n      \n      const regularDeps = descriptor.dependencies?.map(dep => this.resolve(dep)) || [];\n      return descriptor.factory(...regularDeps, ...additionalDeps);\n    };\n  }\n  \n  // Check if service is registered\n  has(token: ServiceToken): boolean {\n    return this.descriptors.has(token);\n  }\n  \n  // Dispose resources\n  dispose(): void {\n    this.singletons.clear();\n    this.scopedInstances.clear();\n    this.descriptors.clear();\n    this.currentScope = null;\n  }\n}\n\n// Decorator support\nfunction Injectable(lifecycle: ServiceDescriptor['lifecycle'] = 'singleton') {\n  return function \u003CT extends { new (...args: any[]): any }>(constructor: T) {\n    const token = constructor;\n    const dependencies = Reflect.getMetadata('design:paramtypes', constructor) || [];\n    \n    // Store metadata for container to use\n    Reflect.defineMetadata('di:lifecycle', lifecycle, constructor);\n    Reflect.defineMetadata('di:dependencies', dependencies, constructor);\n    \n    return constructor;\n  };\n}\n\nfunction Inject(token?: ServiceToken) {\n  return function (target: any, propertyKey: string | symbol, parameterIndex: number) {\n    const existing = Reflect.getMetadata('di:inject', target) || [];\n    existing[parameterIndex] = token || Reflect.getMetadata('design:paramtypes', target)?.[parameterIndex];\n    Reflect.defineMetadata('di:inject', existing, target);\n  };\n}\n\n// Usage examples\n// Service definitions\n@Injectable('singleton')\nclass DatabaseService {\n  connect() {\n    console.log('Database connected');\n  }\n}\n\n@Injectable('scoped')\nclass UserRepository {\n  constructor(private db: DatabaseService) {}\n  \n  getUsers() {\n    return [{ id: 1, name: 'John' }];\n  }\n}\n\n@Injectable('transient')\nclass EmailService {\n  sendEmail(to: string, message: string) {\n    console.log(`Sending email to ${to}: ${message}`);\n  }\n}\n\nclass UserService {\n  constructor(\n    @Inject() private userRepo: UserRepository,\n    @Inject() private emailService: EmailService\n  ) {}\n  \n  notifyUsers() {\n    const users = this.userRepo.getUsers();\n    users.forEach(user => {\n      this.emailService.sendEmail(user.name, 'Notification');\n    });\n  }\n}\n\n// Setup container\nconst container = new DIContainer();\n\n// Register services\ncontainer.registerClass(DatabaseService, DatabaseService, 'singleton');\ncontainer.registerClass(UserRepository, UserRepository, 'scoped');\ncontainer.registerClass(EmailService, EmailService, 'transient');\ncontainer.registerClass(UserService, UserService, 'singleton');\n\n// Manual registration example\ncontainer.register({\n  token: 'Logger',\n  factory: () => ({\n    log: (message: string) => console.log(`[LOG] ${message}`)\n  }),\n  lifecycle: 'singleton'\n});\n\n// Resolve and use\nconst userService = container.resolve(UserService);\nuserService.notifyUsers();\n\n// Using scopes\nconst scope = container.createScope();\nscope.run(() => {\n  const scopedRepo1 = container.resolve(UserRepository);\n  const scopedRepo2 = container.resolve(UserRepository);\n  console.log(scopedRepo1 === scopedRepo2); // true (same scope)\n});\n\n// Factory pattern\nconst userServiceFactory = container.factory(UserService);\nconst userServiceWithCustomDep = userServiceFactory(customDependency);\n\n// Service provider pattern\ninterface ServiceProvider {\n  get\u003CT>(token: ServiceToken\u003CT>): T;\n  has(token: ServiceToken): boolean;\n}\n\nconst serviceProvider: ServiceProvider = container;\n\n// Child containers\nclass ChildContainer extends DIContainer {\n  constructor(private parent: DIContainer) {\n    super();\n  }\n  \n  resolve\u003CT>(token: ServiceToken\u003CT>): T {\n    if (super.has(token)) {\n      return super.resolve(token);\n    }\n    return this.parent.resolve(token);\n  }\n  \n  has(token: ServiceToken): boolean {\n    return super.has(token) || this.parent.has(token);\n  }\n}",{"id":574,"category":480,"title":575,"description":576,"author":9,"date":10,"tags":577,"code":580,"canPreview":488},"ts-config-manager","Type Safe Configuration Manager","Hierarchical configuration management with validation and environment support",[484,578,495,579],"Configuration","Environment","interface ConfigSchema {\n  [key: string]: {\n    type: 'string' | 'number' | 'boolean' | 'object' | 'array';\n    required?: boolean;\n    default?: any;\n    validator?: (value: any) => boolean | string;\n    envVar?: string;\n    transform?: (value: any) => any;\n  };\n}\n\ntype ConfigFromSchema\u003CT extends ConfigSchema> = {\n  [K in keyof T]: T[K]['type'] extends 'string'\n    ? string\n    : T[K]['type'] extends 'number'\n    ? number\n    : T[K]['type'] extends 'boolean'\n    ? boolean\n    : T[K]['type'] extends 'object'\n    ? Record\u003Cstring, any>\n    : T[K]['type'] extends 'array'\n    ? any[]\n    : never;\n};\n\nclass ConfigManager\u003CT extends ConfigSchema> {\n  private config: Partial\u003CConfigFromSchema\u003CT>> = {};\n  private schema: T;\n  private sources: Array\u003CRecord\u003Cstring, any>> = [];\n  \n  constructor(schema: T) {\n    this.schema = schema;\n    this.loadDefaults();\n  }\n  \n  // Load configuration from various sources\n  loadFromObject(source: Record\u003Cstring, any>): this {\n    this.sources.push(source);\n    this.mergeSource(source);\n    return this;\n  }\n  \n  loadFromEnv(prefix = ''): this {\n    const envConfig: Record\u003Cstring, any> = {};\n    \n    for (const [key, def] of Object.entries(this.schema)) {\n      const envKey = def.envVar || `${prefix}${key.toUpperCase()}`;\n      const envValue = process.env[envKey];\n      \n      if (envValue !== undefined) {\n        envConfig[key] = this.parseEnvValue(envValue, def.type);\n      }\n    }\n    \n    return this.loadFromObject(envConfig);\n  }\n  \n  loadFromJSON(json: string): this {\n    try {\n      const parsed = JSON.parse(json);\n      return this.loadFromObject(parsed);\n    } catch (error) {\n      throw new Error(`Invalid JSON configuration: ${error}`);\n    }\n  }\n  \n  loadFromFile(filePath: string): this {\n    // This would be implemented based on runtime (Node.js, Deno, etc.)\n    // For example in Node.js:\n    // const content = fs.readFileSync(filePath, 'utf-8');\n    // return this.loadFromJSON(content);\n    return this;\n  }\n  \n  private parseEnvValue(value: string, type: ConfigSchema[string]['type']): any {\n    switch (type) {\n      case 'string':\n        return value;\n      case 'number':\n        const num = Number(value);\n        if (isNaN(num)) throw new Error(`Invalid number: ${value}`);\n        return num;\n      case 'boolean':\n        if (value.toLowerCase() === 'true' || value === '1') return true;\n        if (value.toLowerCase() === 'false' || value === '0') return false;\n        throw new Error(`Invalid boolean: ${value}`);\n      case 'object':\n        try {\n          return JSON.parse(value);\n        } catch {\n          throw new Error(`Invalid JSON object: ${value}`);\n        }\n      case 'array':\n        try {\n          const parsed = JSON.parse(value);\n          if (!Array.isArray(parsed)) {\n            throw new Error('Not an array');\n          }\n          return parsed;\n        } catch {\n          // Try comma-separated values\n          return value.split(',').map(v => v.trim());\n        }\n    }\n  }\n  \n  private loadDefaults(): void {\n    for (const [key, def] of Object.entries(this.schema)) {\n      if (def.default !== undefined) {\n        this.config[key as keyof T] = def.default;\n      }\n    }\n  }\n  \n  private mergeSource(source: Record\u003Cstring, any>): void {\n    for (const [key, def] of Object.entries(this.schema)) {\n      if (source[key] !== undefined) {\n        let value = source[key];\n        \n        // Apply transform if specified\n        if (def.transform) {\n          value = def.transform(value);\n        }\n        \n        // Validate type\n        value = this.validateAndCast(key, value, def);\n        \n        // Custom validation\n        if (def.validator) {\n          const validationResult = def.validator(value);\n          if (validationResult !== true) {\n            throw new Error(`Validation failed for ${key}: ${validationResult}`);\n          }\n        }\n        \n        this.config[key as keyof T] = value;\n      }\n    }\n  }\n  \n  private validateAndCast(key: string, value: any, def: ConfigSchema[string]): any {\n    const expectedType = def.type;\n    \n    switch (expectedType) {\n      case 'string':\n        if (typeof value !== 'string') {\n          throw new Error(`Expected string for ${key}, got ${typeof value}`);\n        }\n        return value;\n        \n      case 'number':\n        if (typeof value === 'string') {\n          const num = Number(value);\n          if (isNaN(num)) {\n            throw new Error(`Invalid number for ${key}: ${value}`);\n          }\n          return num;\n        }\n        if (typeof value !== 'number') {\n          throw new Error(`Expected number for ${key}, got ${typeof value}`);\n        }\n        return value;\n        \n      case 'boolean':\n        if (typeof value === 'string') {\n          if (value.toLowerCase() === 'true' || value === '1') return true;\n          if (value.toLowerCase() === 'false' || value === '0') return false;\n          throw new Error(`Invalid boolean for ${key}: ${value}`);\n        }\n        if (typeof value !== 'boolean') {\n          throw new Error(`Expected boolean for ${key}, got ${typeof value}`);\n        }\n        return value;\n        \n      case 'object':\n        if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n          throw new Error(`Expected object for ${key}, got ${typeof value}`);\n        }\n        return value;\n        \n      case 'array':\n        if (!Array.isArray(value)) {\n          throw new Error(`Expected array for ${key}, got ${typeof value}`);\n        }\n        return value;\n    }\n  }\n  \n  // Get configuration value\n  get\u003CK extends keyof ConfigFromSchema\u003CT>>(key: K): ConfigFromSchema\u003CT>[K] {\n    const value = this.config[key];\n    \n    if (value === undefined) {\n      const def = this.schema[key as string];\n      if (def.required) {\n        throw new Error(`Required configuration missing: ${String(key)}`);\n      }\n      return def.default;\n    }\n    \n    return value;\n  }\n  \n  getAll(): ConfigFromSchema\u003CT> {\n    const result: any = {};\n    \n    for (const key of Object.keys(this.schema)) {\n      result[key] = this.get(key as any);\n    }\n    \n    return result as ConfigFromSchema\u003CT>;\n  }\n  \n  // Check if configuration is valid\n  validate(): { valid: boolean; errors: string[] } {\n    const errors: string[] = [];\n    \n    for (const [key, def] of Object.entries(this.schema)) {\n      const value = this.config[key];\n      \n      if (def.required && value === undefined) {\n        errors.push(`Required field missing: ${key}`);\n        continue;\n      }\n      \n      if (value !== undefined && def.validator) {\n        const validationResult = def.validator(value);\n        if (validationResult !== true) {\n          errors.push(`Validation failed for ${key}: ${validationResult}`);\n        }\n      }\n    }\n    \n    return {\n      valid: errors.length === 0,\n      errors\n    };\n  }\n  \n  // Create nested configuration\n  createNested\u003CK extends keyof ConfigFromSchema\u003CT>>(\n    key: K,\n    nestedSchema: ConfigSchema\n  ): ConfigManager\u003Cany> {\n    const nestedValue = this.get(key);\n    \n    if (typeof nestedValue !== 'object' || nestedValue === null) {\n      throw new Error(`Cannot create nested config from non-object value: ${String(key)}`);\n    }\n    \n    const nestedConfig = new ConfigManager(nestedSchema);\n    nestedConfig.loadFromObject(nestedValue as Record\u003Cstring, any>);\n    \n    return nestedConfig;\n  }\n  \n  // Override configuration at runtime\n  set\u003CK extends keyof ConfigFromSchema\u003CT>>(key: K, value: ConfigFromSchema\u003CT>[K]): void {\n    const def = this.schema[key as string];\n    if (!def) {\n      throw new Error(`Unknown configuration key: ${String(key)}`);\n    }\n    \n    const validated = this.validateAndCast(key as string, value, def);\n    \n    if (def.validator) {\n      const validationResult = def.validator(validated);\n      if (validationResult !== true) {\n        throw new Error(`Validation failed: ${validationResult}`);\n      }\n    }\n    \n    this.config[key] = validated;\n  }\n}\n\n// Usage examples\nconst appConfigSchema = {\n  server: {\n    type: 'object' as const,\n    required: true,\n    default: {},\n    validator: (value) => {\n      if (!value.port || typeof value.port !== 'number') {\n        return 'Port must be a number';\n      }\n      if (value.port \u003C 1 || value.port > 65535) {\n        return 'Port must be between 1 and 65535';\n      }\n      return true;\n    }\n  },\n  database: {\n    type: 'object' as const,\n    required: true,\n    envVar: 'DB_CONFIG'\n  },\n  logging: {\n    type: 'object' as const,\n    default: { level: 'info', format: 'json' },\n    validator: (value) => {\n      const validLevels = ['error', 'warn', 'info', 'debug'];\n      if (!validLevels.includes(value.level)) {\n        return `Log level must be one of: ${validLevels.join(', ')}`;\n      }\n      return true;\n    }\n  },\n  features: {\n    type: 'object' as const,\n    default: { analytics: false, caching: true }\n  },\n  cors: {\n    type: 'object' as const,\n    default: { enabled: true, origins: ['localhost'] }\n  },\n  rateLimit: {\n    type: 'number' as const,\n    default: 100,\n    validator: (value) => value > 0 || 'Rate limit must be positive'\n  }\n};\n\n// Create configuration manager\nconst config = new ConfigManager(appConfigSchema)\n  .loadFromObject({\n    server: { port: 3000, host: '0.0.0.0' },\n    database: { url: 'postgres://localhost:5432/app' }\n  })\n  .loadFromEnv('APP_');\n\n// Access configuration\nconst serverConfig = config.get('server');\nconsole.log(`Server port: ${serverConfig.port}`);\n\n// Validate\nconst validation = config.validate();\nif (!validation.valid) {\n  console.error('Configuration errors:', validation.errors);\n}\n\n// Nested configuration\nconst loggingConfig = config.createNested('logging', {\n  level: { type: 'string' as const, required: true },\n  format: { type: 'string' as const, default: 'json' }\n});\n\nconsole.log('Log level:', loggingConfig.get('level'));\n\n// Runtime override\nconfig.set('rateLimit', 200);\n\n// Type-safe access\ntype AppConfig = ConfigFromSchema\u003Ctypeof appConfigSchema>;\n\n// Configuration builder pattern\nclass ConfigBuilder\u003CT extends ConfigSchema> {\n  private configManager: ConfigManager\u003CT>;\n  \n  constructor(schema: T) {\n    this.configManager = new ConfigManager(schema);\n  }\n  \n  withDefaults(defaults: Partial\u003CConfigFromSchema\u003CT>>): this {\n    this.configManager.loadFromObject(defaults as any);\n    return this;\n  }\n  \n  withEnvironment(prefix = ''): this {\n    this.configManager.loadFromEnv(prefix);\n    return this;\n  }\n  \n  withFile(filePath: string): this {\n    this.configManager.loadFromFile(filePath);\n    return this;\n  }\n  \n  build(): ConfigManager\u003CT> {\n    const validation = this.configManager.validate();\n    if (!validation.valid) {\n      throw new Error(`Configuration invalid: ${validation.errors.join(', ')}`);\n    }\n    return this.configManager;\n  }\n}\n\n// Builder usage\nconst appConfig = new ConfigBuilder(appConfigSchema)\n  .withDefaults({\n    server: { port: 3000 },\n    logging: { level: 'info' }\n  })\n  .withEnvironment('APP_')\n  .build();",{"id":582,"category":480,"title":583,"description":584,"author":9,"date":10,"tags":585,"code":588,"canPreview":488},"ts-middleware-pipeline","Middleware Pipeline Pattern","Composable middleware pipeline for request/response processing",[484,586,587,511],"Middleware","Pipeline","type Middleware\u003CT> = (\n  context: T,\n  next: () => Promise\u003Cvoid> | void\n) => Promise\u003Cvoid> | void;\n\nclass Pipeline\u003CT> {\n  private middlewares: Middleware\u003CT>[] = [];\n  private errorHandlers: Array\u003C{\n    predicate: (error: any) => boolean;\n    handler: (context: T, error: any) => Promise\u003Cvoid> | void;\n  }> = [];\n  \n  // Add middleware to the pipeline\n  use(middleware: Middleware\u003CT>): this {\n    this.middlewares.push(middleware);\n    return this;\n  }\n  \n  // Add error handler\n  catch(\n    predicate: (error: any) => boolean,\n    handler: (context: T, error: any) => Promise\u003Cvoid> | void\n  ): this {\n    this.errorHandlers.push({ predicate, handler });\n    return this;\n  }\n  \n  // Execute the pipeline\n  async execute(context: T): Promise\u003Cvoid> {\n    let index = 0;\n    \n    const next = async (): Promise\u003Cvoid> => {\n      if (index \u003C this.middlewares.length) {\n        const middleware = this.middlewares[index++];\n        try {\n          await middleware(context, next);\n        } catch (error) {\n          await this.handleError(context, error);\n        }\n      }\n    };\n    \n    try {\n      await next();\n    } catch (error) {\n      await this.handleError(context, error);\n    }\n  }\n  \n  private async handleError(context: T, error: any): Promise\u003Cvoid> {\n    for (const { predicate, handler } of this.errorHandlers) {\n      if (predicate(error)) {\n        await handler(context, error);\n        return;\n      }\n    }\n    throw error; // Re-throw if no handler matches\n  }\n  \n  // Compose multiple pipelines\n  static compose\u003CT>(pipelines: Pipeline\u003CT>[]): Pipeline\u003CT> {\n    const combined = new Pipeline\u003CT>();\n    \n    for (const pipeline of pipelines) {\n      combined.middlewares.push(...pipeline.middlewares);\n      combined.errorHandlers.push(...pipeline.errorHandlers);\n    }\n    \n    return combined;\n  }\n  \n  // Create a pipeline from middleware array\n  static from\u003CT>(middlewares: Middleware\u003CT>[]): Pipeline\u003CT> {\n    const pipeline = new Pipeline\u003CT>();\n    pipeline.middlewares = [...middlewares];\n    return pipeline;\n  }\n}\n\n// Common middleware types\ninterface RequestContext {\n  request: {\n    method: string;\n    url: string;\n    headers: Record\u003Cstring, string>;\n    body?: any;\n    params?: Record\u003Cstring, string>;\n    query?: Record\u003Cstring, string>;\n  };\n  response: {\n    statusCode: number;\n    headers: Record\u003Cstring, string>;\n    body?: any;\n    send: (body: any) => void;\n    json: (data: any) => void;\n  };\n  state: Record\u003Cstring, any>;\n}\n\n// Utility middleware factories\nconst middlewareFactories = {\n  // Logging middleware\n  logger(): Middleware\u003CRequestContext> {\n    return async (context, next) => {\n      const start = Date.now();\n      console.log(`→ ${context.request.method} ${context.request.url}`);\n      \n      await next();\n      \n      const duration = Date.now() - start;\n      console.log(`← ${context.response.statusCode} ${duration}ms`);\n    };\n  },\n  \n  // JSON body parsing\n  jsonBodyParser(): Middleware\u003CRequestContext> {\n    return async (context, next) => {\n      const contentType = context.request.headers['content-type'] || '';\n      \n      if (contentType.includes('application/json')) {\n        try {\n          // In real implementation, you'd parse the body from the request\n          // For example: context.request.body = await parseJsonBody(context.request);\n        } catch (error) {\n          context.response.statusCode = 400;\n          context.response.json({ error: 'Invalid JSON' });\n          return;\n        }\n      }\n      \n      await next();\n    };\n  },\n  \n  // CORS middleware\n  cors(options: {\n    origin?: string | string[] | ((origin: string) => string | null);\n    methods?: string[];\n    headers?: string[];\n    credentials?: boolean;\n  } = {}): Middleware\u003CRequestContext> {\n    return async (context, next) => {\n      const origin = context.request.headers.origin;\n      \n      if (origin) {\n        let allowedOrigin: string | null = null;\n        \n        if (typeof options.origin === 'function') {\n          allowedOrigin = options.origin(origin);\n        } else if (Array.isArray(options.origin)) {\n          if (options.origin.includes(origin) || options.origin.includes('*')) {\n            allowedOrigin = origin;\n          }\n        } else if (options.origin === '*' || options.origin === origin) {\n          allowedOrigin = origin;\n        }\n        \n        if (allowedOrigin) {\n          context.response.headers['Access-Control-Allow-Origin'] = allowedOrigin;\n          \n          if (options.credentials) {\n            context.response.headers['Access-Control-Allow-Credentials'] = 'true';\n          }\n          \n          if (context.request.method === 'OPTIONS') {\n            // Preflight request\n            if (options.methods) {\n              context.response.headers['Access-Control-Allow-Methods'] = options.methods.join(', ');\n            }\n            if (options.headers) {\n              context.response.headers['Access-Control-Allow-Headers'] = options.headers.join(', ');\n            }\n            context.response.statusCode = 204;\n            return;\n          }\n        }\n      }\n      \n      await next();\n    };\n  },\n  \n  // Authentication middleware\n  authenticate(\n    verifier: (token: string) => Promise\u003Cany>,\n    options: { header?: string; cookie?: string } = {}\n  ): Middleware\u003CRequestContext> {\n    return async (context, next) => {\n      let token: string | undefined;\n      \n      // Try to get token from header\n      if (options.header) {\n        const authHeader = context.request.headers[options.header.toLowerCase()];\n        if (authHeader?.startsWith('Bearer ')) {\n          token = authHeader.slice(7);\n        }\n      }\n      \n      // Try to get token from cookie\n      if (!token && options.cookie) {\n        const cookies = context.request.headers.cookie || '';\n        const cookieMatch = cookies.match(new RegExp(`${options.cookie}=([^;]+)`));\n        if (cookieMatch) {\n          token = cookieMatch[1];\n        }\n      }\n      \n      if (!token) {\n        context.response.statusCode = 401;\n        context.response.json({ error: 'Authentication required' });\n        return;\n      }\n      \n      try {\n        const user = await verifier(token);\n        context.state.user = user;\n        await next();\n      } catch (error) {\n        context.response.statusCode = 401;\n        context.response.json({ error: 'Invalid token' });\n      }\n    };\n  },\n  \n  // Rate limiting middleware\n  rateLimit(options: {\n    windowMs: number;\n    max: number;\n    keyGenerator?: (context: RequestContext) => string;\n  }): Middleware\u003CRequestContext> {\n    const store = new Map\u003Cstring, { count: number; resetTime: number }>();\n    \n    return async (context, next) => {\n      const key = options.keyGenerator?.(context) || context.request.headers['x-forwarded-for'] || 'anonymous';\n      const now = Date.now();\n      \n      let entry = store.get(key);\n      \n      if (!entry || now > entry.resetTime) {\n        entry = { count: 0, resetTime: now + options.windowMs };\n        store.set(key, entry);\n      }\n      \n      if (entry.count >= options.max) {\n        context.response.statusCode = 429;\n        context.response.headers['Retry-After'] = Math.ceil((entry.resetTime - now) / 1000).toString();\n        context.response.json({ error: 'Too many requests' });\n        return;\n      }\n      \n      entry.count++;\n      context.response.headers['X-RateLimit-Limit'] = options.max.toString();\n      context.response.headers['X-RateLimit-Remaining'] = (options.max - entry.count).toString();\n      context.response.headers['X-RateLimit-Reset'] = Math.ceil(entry.resetTime / 1000).toString();\n      \n      await next();\n    };\n  }\n};\n\n// Generic middleware utilities\nconst middlewareUtils = {\n  // Conditional middleware\n  if(\n    condition: (context: any) => boolean,\n    trueMiddleware: Middleware\u003Cany>,\n    falseMiddleware?: Middleware\u003Cany>\n  ): Middleware\u003Cany> {\n    return async (context, next) => {\n      if (condition(context)) {\n        await trueMiddleware(context, next);\n      } else if (falseMiddleware) {\n        await falseMiddleware(context, next);\n      } else {\n        await next();\n      }\n    };\n  },\n  \n  // Timeout middleware\n  timeout(ms: number): Middleware\u003Cany> {\n    return async (context, next) => {\n      const timeoutPromise = new Promise((_, reject) => {\n        setTimeout(() => reject(new Error('Request timeout')), ms);\n      });\n      \n      await Promise.race([next(), timeoutPromise]);\n    };\n  },\n  \n  // Compose multiple middleware into one\n  compose\u003CT>(middlewares: Middleware\u003CT>[]): Middleware\u003CT> {\n    return async (context, next) => {\n      let index = 0;\n      const composedNext = async () => {\n        if (index \u003C middlewares.length) {\n          const middleware = middlewares[index++];\n          await middleware(context, composedNext);\n        } else {\n          await next();\n        }\n      };\n      await composedNext();\n    };\n  }\n};\n\n// Usage examples\nconst apiPipeline = new Pipeline\u003CRequestContext>()\n  .use(middlewareFactories.logger())\n  .use(middlewareFactories.cors({\n    origin: ['http://localhost:3000', 'https://example.com'],\n    credentials: true\n  }))\n  .use(middlewareFactories.jsonBodyParser())\n  .use(middlewareFactories.rateLimit({\n    windowMs: 15 * 60 * 1000, // 15 minutes\n    max: 100\n  }))\n  .use(middlewareFactories.authenticate(\n    async (token) => {\n      // Verify JWT token\n      return { id: 1, name: 'John' };\n    },\n    { header: 'authorization' }\n  ))\n  .catch(\n    (error) => error.status === 404,\n    (context, error) => {\n      context.response.statusCode = 404;\n      context.response.json({ error: 'Not found' });\n    }\n  )\n  .catch(\n    (error) => error.message === 'Request timeout',\n    (context, error) => {\n      context.response.statusCode = 504;\n      context.response.json({ error: 'Gateway timeout' });\n    }\n  );\n\n// Simulate request processing\nasync function processRequest(request: any) {\n  const context: RequestContext = {\n    request,\n    response: {\n      statusCode: 200,\n      headers: {},\n      send: (body) => console.log('Response:', body),\n      json: (data) => console.log('JSON Response:', data)\n    },\n    state: {}\n  };\n  \n  await apiPipeline.execute(context);\n  return context.response;\n}\n\n// Create specialized pipelines\nconst publicApiPipeline = new Pipeline\u003CRequestContext>()\n  .use(middlewareFactories.logger())\n  .use(middlewareFactories.cors())\n  .use(middlewareFactories.jsonBodyParser());\n\nconst adminApiPipeline = new Pipeline\u003CRequestContext>()\n  .use(middlewareFactories.authenticate(\n    async (token) => {\n      // Admin token verification\n      return { id: 1, role: 'admin' };\n    }\n  ))\n  .use((context, next) => {\n    if (context.state.user?.role !== 'admin') {\n      context.response.statusCode = 403;\n      context.response.json({ error: 'Admin access required' });\n      return;\n    }\n    return next();\n  });\n\n// Combine pipelines\nconst combinedPipeline = Pipeline.compose([publicApiPipeline, adminApiPipeline]);\n\n// Middleware for validation\nfunction validate(schema: any): Middleware\u003CRequestContext> {\n  return async (context, next) => {\n    try {\n      // Validate request body against schema\n      // For example using Zod, Joi, or class-validator\n      await next();\n    } catch (validationError) {\n      context.response.statusCode = 400;\n      context.response.json({ error: 'Validation failed', details: validationError });\n    }\n  };\n}",{"id":590,"category":480,"title":591,"description":592,"author":9,"date":10,"tags":593,"code":595,"canPreview":488},"ts-immutable-builder","Immutable Data Builder","Builder pattern for creating immutable data structures with structural sharing",[484,594,534,526],"Immutable","// Base immutable type\ntype Immutable\u003CT> = T extends Function ? T : T extends object ? { readonly [K in keyof T]: Immutable\u003CT[K]> } : T;\n\n// Utility type for mutable version\ntype Mutable\u003CT> = T extends Function ? T : T extends object ? { -readonly [K in keyof T]: Mutable\u003CT[K]> } : T;\n\nclass ImmutableBuilder\u003CT extends object> {\n  private data: Mutable\u003CT>;\n  \n  constructor(initialData: T) {\n    // Deep clone to ensure immutability\n    this.data = this.deepClone(initialData);\n  }\n  \n  // Create a new builder from existing data\n  static from\u003CT extends object>(data: T): ImmutableBuilder\u003CT> {\n    return new ImmutableBuilder(data);\n  }\n  \n  // Set a value at a specific path\n  set\u003CK extends keyof T>(key: K, value: Immutable\u003CT[K]>): ImmutableBuilder\u003CT> {\n    const newData = this.cloneWithChange(key, value);\n    return new ImmutableBuilder(newData as T);\n  }\n  \n  // Update a value using a transformation function\n  update\u003CK extends keyof T>(\n    key: K,\n    updater: (value: Immutable\u003CT[K]>) => Immutable\u003CT[K]>\n  ): ImmutableBuilder\u003CT> {\n    const currentValue = this.data[key];\n    const newValue = updater(currentValue as Immutable\u003CT[K]>);\n    return this.set(key, newValue);\n  }\n  \n  // Merge with another object\n  merge(partial: Partial\u003CT>): ImmutableBuilder\u003CT> {\n    const newData = { ...this.data, ...partial } as Mutable\u003CT>;\n    return new ImmutableBuilder(newData as T);\n  }\n  \n  // Deep merge\n  deepMerge(partial: Partial\u003CMutable\u003CT>>): ImmutableBuilder\u003CT> {\n    const newData = this.deepMergeObjects(this.data, partial);\n    return new ImmutableBuilder(newData as T);\n  }\n  \n  // Delete a property\n  delete\u003CK extends keyof T>(key: K): ImmutableBuilder\u003COmit\u003CT, K>> {\n    const newData = { ...this.data };\n    delete newData[key];\n    return new ImmutableBuilder(newData as Omit\u003CT, K>);\n  }\n  \n  // Modify nested properties using a lens-like pattern\n  lens\u003CK1 extends keyof T, K2 extends keyof T[K1]>(\n    key1: K1,\n    key2: K2\n  ): {\n    set: (value: Immutable\u003CT[K1][K2]>) => ImmutableBuilder\u003CT>;\n    update: (updater: (value: Immutable\u003CT[K1][K2]>) => Immutable\u003CT[K1][K2]>) => ImmutableBuilder\u003CT>;\n  } {\n    return {\n      set: (value) => {\n        const nested = { ...this.data[key1] as object, [key2]: value } as T[K1];\n        return this.set(key1, nested);\n      },\n      update: (updater) => {\n        const current = this.data[key1]?.[key2];\n        const updated = updater(current as Immutable\u003CT[K1][K2]>);\n        return this.lens(key1, key2).set(updated);\n      }\n    };\n  }\n  \n  // Build the immutable object\n  build(): Immutable\u003CT> {\n    return this.deepFreeze(this.data) as Immutable\u003CT>;\n  }\n  \n  // Get current mutable data (for inspection only)\n  peek(): T {\n    return this.data as T;\n  }\n  \n  // Clone with structural sharing\n  private cloneWithChange\u003CK extends keyof T>(\n    key: K,\n    value: Immutable\u003CT[K]>\n  ): Mutable\u003CT> {\n    return {\n      ...this.data,\n      [key]: this.isObject(value) ? this.deepClone(value) : value\n    } as Mutable\u003CT>;\n  }\n  \n  // Deep clone utility\n  private deepClone\u003CT>(obj: T): Mutable\u003CT> {\n    if (obj === null || typeof obj !== 'object') {\n      return obj as Mutable\u003CT>;\n    }\n    \n    if (Array.isArray(obj)) {\n      return obj.map(item => this.deepClone(item)) as Mutable\u003CT>;\n    }\n    \n    const cloned: any = {};\n    for (const key in obj) {\n      if (Object.prototype.hasOwnProperty.call(obj, key)) {\n        cloned[key] = this.deepClone(obj[key]);\n      }\n    }\n    \n    return cloned as Mutable\u003CT>;\n  }\n  \n  // Deep merge utility\n  private deepMergeObjects\u003CT extends object, U extends Partial\u003CMutable\u003CT>>>(\n    target: T,\n    source: U\n  ): Mutable\u003CT> {\n    const result = { ...target } as any;\n    \n    for (const key in source) {\n      if (source[key] !== undefined) {\n        if (this.isObject(source[key]) && this.isObject(result[key])) {\n          result[key] = this.deepMergeObjects(result[key], source[key] as any);\n        } else if (Array.isArray(source[key]) && Array.isArray(result[key])) {\n          result[key] = [...result[key], ...(source[key] as any)];\n        } else {\n          result[key] = this.isObject(source[key]) \n            ? this.deepClone(source[key])\n            : source[key];\n        }\n      }\n    }\n    \n    return result as Mutable\u003CT>;\n  }\n  \n  // Deep freeze utility\n  private deepFreeze\u003CT>(obj: T): Immutable\u003CT> {\n    if (obj === null || typeof obj !== 'object') {\n      return obj as Immutable\u003CT>;\n    }\n    \n    // Prevent this function from being frozen\n    if (Object.isFrozen(obj)) {\n      return obj as Immutable\u003CT>;\n    }\n    \n    Object.freeze(obj);\n    \n    // Recursively freeze all properties\n    for (const key in obj) {\n      if (Object.prototype.hasOwnProperty.call(obj, key)) {\n        const value = obj[key];\n        if (typeof value === 'object' && value !== null) {\n          this.deepFreeze(value);\n        }\n      }\n    }\n    \n    return obj as Immutable\u003CT>;\n  }\n  \n  private isObject(value: any): value is object {\n    return value !== null && typeof value === 'object';\n  }\n}\n\n// Record-based immutable data structure\nclass ImmutableRecord\u003CT extends Record\u003Cstring, any>> {\n  private data: Immutable\u003CT>;\n  \n  private constructor(data: T) {\n    this.data = new ImmutableBuilder(data).build();\n  }\n  \n  // Factory methods\n  static create\u003CT extends Record\u003Cstring, any>>(initialData: T): ImmutableRecord\u003CT> {\n    return new ImmutableRecord(initialData);\n  }\n  \n  static empty\u003CT extends Record\u003Cstring, any>>(): ImmutableRecord\u003CT> {\n    return new ImmutableRecord({} as T);\n  }\n  \n  // Get value\n  get\u003CK extends keyof T>(key: K): Immutable\u003CT[K]> {\n    return this.data[key];\n  }\n  \n  // Check if has key\n  has\u003CK extends keyof T>(key: K): boolean {\n    return key in this.data;\n  }\n  \n  // Set value (returns new record)\n  set\u003CK extends keyof T>(key: K, value: T[K]): ImmutableRecord\u003CT> {\n    const builder = new ImmutableBuilder(this.data as T);\n    const newData = builder.set(key, value).build();\n    return new ImmutableRecord(newData as T);\n  }\n  \n  // Update value (returns new record)\n  update\u003CK extends keyof T>(\n    key: K,\n    updater: (value: Immutable\u003CT[K]>) => T[K]\n  ): ImmutableRecord\u003CT> {\n    const current = this.get(key);\n    const updated = updater(current);\n    return this.set(key, updated);\n  }\n  \n  // Merge with another record\n  merge(other: Partial\u003CT>): ImmutableRecord\u003CT> {\n    const builder = new ImmutableBuilder(this.data as T);\n    const newData = builder.merge(other).build();\n    return new ImmutableRecord(newData as T);\n  }\n  \n  // Delete a key\n  delete\u003CK extends keyof T>(key: K): ImmutableRecord\u003COmit\u003CT, K>> {\n    const builder = new ImmutableBuilder(this.data as T);\n    const newData = builder.delete(key).build();\n    return new ImmutableRecord(newData as Omit\u003CT, K>);\n  }\n  \n  // Map over entries\n  map\u003CU>(fn: (value: Immutable\u003CT[keyof T]>, key: keyof T) => U): U[] {\n    return Object.entries(this.data).map(([key, value]) => \n      fn(value as Immutable\u003CT[keyof T]>, key as keyof T)\n    );\n  }\n  \n  // Filter entries\n  filter(predicate: (value: Immutable\u003CT[keyof T]>, key: keyof T) => boolean): Partial\u003CT> {\n    const result: Partial\u003CT> = {};\n    \n    for (const key in this.data) {\n      const value = this.data[key];\n      if (predicate(value, key as keyof T)) {\n        result[key] = value;\n      }\n    }\n    \n    return result;\n  }\n  \n  // Reduce over entries\n  reduce\u003CU>(\n    fn: (acc: U, value: Immutable\u003CT[keyof T]>, key: keyof T) => U,\n    initialValue: U\n  ): U {\n    let acc = initialValue;\n    \n    for (const key in this.data) {\n      const value = this.data[key];\n      acc = fn(acc, value, key as keyof T);\n    }\n    \n    return acc;\n  }\n  \n  // Convert to plain object\n  toObject(): Immutable\u003CT> {\n    return this.data;\n  }\n  \n  // Get keys\n  keys(): (keyof T)[] {\n    return Object.keys(this.data) as (keyof T)[];\n  }\n  \n  // Get values\n  values(): Immutable\u003CT[keyof T]>[] {\n    return Object.values(this.data);\n  }\n  \n  // Get entries\n  entries(): [keyof T, Immutable\u003CT[keyof T]>][] {\n    return Object.entries(this.data) as [keyof T, Immutable\u003CT[keyof T]>][];\n  }\n  \n  // Get size\n  size(): number {\n    return this.keys().length;\n  }\n}\n\n// Usage examples\ninterface User {\n  id: number;\n  name: string;\n  email: string;\n  profile: {\n    age: number;\n    address: {\n      street: string;\n      city: string;\n    };\n  };\n  preferences: {\n    theme: 'light' | 'dark';\n    notifications: boolean;\n  };\n}\n\n// Create immutable user\nconst userBuilder = new ImmutableBuilder\u003CUser>({\n  id: 1,\n  name: 'John Doe',\n  email: 'john@example.com',\n  profile: {\n    age: 30,\n    address: {\n      street: '123 Main St',\n      city: 'New York'\n    }\n  },\n  preferences: {\n    theme: 'light',\n    notifications: true\n  }\n});\n\n// Apply transformations\nconst updatedUser = userBuilder\n  .set('name', 'John Smith')\n  .update('profile', profile => ({\n    ...profile,\n    age: 31\n  }))\n  .lens('profile', 'address')\n    .set({ street: '456 Oak Ave', city: 'Boston' })\n  .update('preferences', prefs => ({\n    ...prefs,\n    theme: 'dark'\n  }))\n  .build();\n\nconsole.log(updatedUser.name); // 'John Smith'\nconsole.log(updatedUser.profile.age); // 31\n\n// Try to mutate (will fail in strict mode)\n// updatedUser.name = 'Jane'; // Error: Cannot assign to read-only property\n\n// Using ImmutableRecord\nconst userRecord = ImmutableRecord.create({\n  id: 1,\n  name: 'Alice',\n  active: true\n});\n\nconst updatedRecord = userRecord\n  .set('name', 'Alice Smith')\n  .set('active', false)\n  .merge({ email: 'alice@example.com' });\n\nconsole.log(updatedRecord.get('name')); // 'Alice Smith'\nconsole.log(updatedRecord.has('email')); // true\n\n// Complex transformation with structural sharing\nconst data = {\n  users: {\n    '1': { name: 'John', age: 30 },\n    '2': { name: 'Jane', age: 25 }\n  },\n  metadata: {\n    count: 2,\n    timestamp: Date.now()\n  }\n};\n\nconst builder = new ImmutableBuilder(data);\nconst updated = builder\n  .lens('users', '1')\n    .set({ name: 'Jonathan', age: 31 })\n  .update('metadata', meta => ({\n    ...meta,\n    count: 3,\n    updated: true\n  }))\n  .build();\n\nconsole.log(updated.users['1'].name); // 'Jonathan'\nconsole.log(data.users['1'].name); // 'John' (original unchanged)\n\n// Batch updates\nfunction batchUpdate\u003CT extends object>(\n  data: T,\n  updates: Array\u003C(builder: ImmutableBuilder\u003CT>) => ImmutableBuilder\u003CT>>\n): Immutable\u003CT> {\n  let builder = new ImmutableBuilder(data);\n  for (const update of updates) {\n    builder = update(builder);\n  }\n  return builder.build();\n}\n\nconst batchUpdated = batchUpdate(data, [\n  builder => builder.lens('users', '1').set({ name: 'Updated', age: 99 }),\n  builder => builder.update('metadata', meta => ({ ...meta, batch: true }))\n]);",{"id":597,"category":480,"title":598,"description":599,"author":9,"date":10,"tags":600,"code":604,"canPreview":488},"ts-scheduler-queue","Priority Scheduler Queue","Priority-based task scheduler with concurrency control and task dependency management",[484,601,602,603],"Scheduler","Queue","Concurrency","interface Task\u003CT = any> {\n  id: string;\n  priority: number; // Higher number = higher priority\n  execute: () => Promise\u003CT>;\n  dependencies?: string[]; // IDs of tasks that must complete first\n  timeout?: number; // Timeout in milliseconds\n  retries?: number; // Number of retry attempts\n  onSuccess?: (result: T) => void;\n  onError?: (error: any) => void;\n  onComplete?: () => void;\n}\n\ninterface TaskResult\u003CT = any> {\n  id: string;\n  success: boolean;\n  result?: T;\n  error?: any;\n  duration: number;\n  retries: number;\n}\n\ninterface SchedulerOptions {\n  maxConcurrent: number;\n  defaultPriority?: number;\n  defaultTimeout?: number;\n  defaultRetries?: number;\n  onQueueChange?: (queueSize: number, running: number) => void;\n}\n\nclass PriorityScheduler {\n  private pendingTasks: Array\u003CTask> = [];\n  private runningTasks = new Map\u003Cstring, { task: Task; startTime: number }>();\n  private completedTasks = new Map\u003Cstring, TaskResult>();\n  private taskDependencies = new Map\u003Cstring, Set\u003Cstring>>();\n  private options: Required\u003COmit\u003CSchedulerOptions, 'onQueueChange'>> & {\n    onQueueChange?: (queueSize: number, running: number) => void;\n  };\n  private isProcessing = false;\n  private idCounter = 0;\n  \n  constructor(options: SchedulerOptions) {\n    this.options = {\n      defaultPriority: 0,\n      defaultTimeout: 30000,\n      defaultRetries: 0,\n      ...options\n    };\n  }\n  \n  // Add a task to the scheduler\n  addTask\u003CT>(task: Omit\u003CTask\u003CT>, 'id'>, id?: string): string {\n    const taskId = id || `task_${++this.idCounter}`;\n    \n    const fullTask: Task\u003CT> = {\n      id: taskId,\n      priority: task.priority ?? this.options.defaultPriority,\n      timeout: task.timeout ?? this.options.defaultTimeout,\n      retries: task.retries ?? this.options.defaultRetries,\n      ...task\n    };\n    \n    // Set up dependencies\n    if (fullTask.dependencies && fullTask.dependencies.length > 0) {\n      this.taskDependencies.set(taskId, new Set(fullTask.dependencies));\n    }\n    \n    this.pendingTasks.push(fullTask);\n    this.sortTasks();\n    this.notifyQueueChange();\n    this.processQueue();\n    \n    return taskId;\n  }\n  \n  // Add multiple tasks\n  addTasks(tasks: Array\u003COmit\u003CTask, 'id'>>): string[] {\n    return tasks.map(task => this.addTask(task));\n  }\n  \n  // Remove a task (if not running)\n  removeTask(taskId: string): boolean {\n    const index = this.pendingTasks.findIndex(task => task.id === taskId);\n    if (index !== -1) {\n      this.pendingTasks.splice(index, 1);\n      this.taskDependencies.delete(taskId);\n      this.notifyQueueChange();\n      return true;\n    }\n    \n    // Clean up dependencies pointing to this task\n    for (const [id, deps] of this.taskDependencies.entries()) {\n      if (deps.has(taskId)) {\n        deps.delete(taskId);\n      }\n    }\n    \n    return false;\n  }\n  \n  // Get task status\n  getTaskStatus(taskId: string): 'pending' | 'running' | 'completed' | 'not-found' {\n    if (this.runningTasks.has(taskId)) return 'running';\n    if (this.completedTasks.has(taskId)) return 'completed';\n    if (this.pendingTasks.some(task => task.id === taskId)) return 'pending';\n    return 'not-found';\n  }\n  \n  // Get task result\n  getTaskResult\u003CT>(taskId: string): TaskResult\u003CT> | undefined {\n    return this.completedTasks.get(taskId) as TaskResult\u003CT> | undefined;\n  }\n  \n  // Wait for a specific task to complete\n  async waitForTask\u003CT>(taskId: string, timeout?: number): Promise\u003CTaskResult\u003CT>> {\n    return new Promise((resolve, reject) => {\n      const startTime = Date.now();\n      \n      const checkInterval = setInterval(() => {\n        const result = this.completedTasks.get(taskId);\n        \n        if (result) {\n          clearInterval(checkInterval);\n          resolve(result as TaskResult\u003CT>);\n          return;\n        }\n        \n        if (timeout && Date.now() - startTime > timeout) {\n          clearInterval(checkInterval);\n          reject(new Error(`Timeout waiting for task ${taskId}`));\n        }\n        \n        // Check if task doesn't exist\n        if (this.getTaskStatus(taskId) === 'not-found') {\n          clearInterval(checkInterval);\n          reject(new Error(`Task ${taskId} not found`));\n        }\n      }, 100);\n    });\n  }\n  \n  // Wait for all tasks to complete\n  async waitForAll(timeout?: number): Promise\u003CMap\u003Cstring, TaskResult>> {\n    return new Promise((resolve, reject) => {\n      const startTime = Date.now();\n      \n      const checkInterval = setInterval(() => {\n        if (this.pendingTasks.length === 0 && this.runningTasks.size === 0) {\n          clearInterval(checkInterval);\n          resolve(new Map(this.completedTasks));\n          return;\n        }\n        \n        if (timeout && Date.now() - startTime > timeout) {\n          clearInterval(checkInterval);\n          reject(new Error('Timeout waiting for all tasks'));\n        }\n      }, 100);\n    });\n  }\n  \n  // Get queue statistics\n  getStats() {\n    return {\n      pending: this.pendingTasks.length,\n      running: this.runningTasks.size,\n      completed: this.completedTasks.size,\n      maxConcurrent: this.options.maxConcurrent\n    };\n  }\n  \n  // Pause scheduler (won't start new tasks)\n  pause(): void {\n    this.isProcessing = false;\n  }\n  \n  // Resume scheduler\n  resume(): void {\n    if (!this.isProcessing) {\n      this.isProcessing = true;\n      this.processQueue();\n    }\n  }\n  \n  // Clear all pending tasks\n  clearPending(): void {\n    this.pendingTasks = [];\n    this.taskDependencies.clear();\n    this.notifyQueueChange();\n  }\n  \n  // Cancel all tasks\n  async cancelAll(): Promise\u003Cvoid> {\n    this.clearPending();\n    \n    // Wait for running tasks to complete\n    await this.waitForAll();\n  }\n  \n  private async processQueue(): Promise\u003Cvoid> {\n    if (this.isProcessing || this.pendingTasks.length === 0) {\n      return;\n    }\n    \n    this.isProcessing = true;\n    \n    while (\n      this.pendingTasks.length > 0 &&\n      this.runningTasks.size \u003C this.options.maxConcurrent\n    ) {\n      // Find next runnable task (considering dependencies)\n      const nextTaskIndex = this.findNextRunnableTask();\n      \n      if (nextTaskIndex === -1) {\n        // No runnable tasks at the moment\n        break;\n      }\n      \n      const task = this.pendingTasks.splice(nextTaskIndex, 1)[0];\n      this.runTask(task);\n    }\n    \n    this.isProcessing = false;\n    this.notifyQueueChange();\n  }\n  \n  private findNextRunnableTask(): number {\n    for (let i = 0; i \u003C this.pendingTasks.length; i++) {\n      const task = this.pendingTasks[i];\n      \n      // Check dependencies\n      const deps = this.taskDependencies.get(task.id);\n      if (deps && deps.size > 0) {\n        // Check if all dependencies are completed\n        const allDepsCompleted = Array.from(deps).every(\n          depId => this.completedTasks.has(depId)\n        );\n        \n        if (!allDepsCompleted) {\n          continue;\n        }\n      }\n      \n      return i;\n    }\n    \n    return -1;\n  }\n  \n  private async runTask\u003CT>(task: Task\u003CT>): Promise\u003Cvoid> {\n    const startTime = Date.now();\n    this.runningTasks.set(task.id, { task, startTime });\n    \n    let retries = 0;\n    const maxRetries = task.retries ?? 0;\n    \n    const executeWithRetry = async (): Promise\u003CTaskResult\u003CT>> => {\n      try {\n        const result = await this.executeWithTimeout(task);\n        \n        return {\n          id: task.id,\n          success: true,\n          result,\n          duration: Date.now() - startTime,\n          retries\n        };\n      } catch (error) {\n        if (retries \u003C maxRetries) {\n          retries++;\n          return executeWithRetry();\n        }\n        \n        return {\n          id: task.id,\n          success: false,\n          error,\n          duration: Date.now() - startTime,\n          retries\n        };\n      }\n    };\n    \n    const result = await executeWithRetry();\n    \n    // Clean up\n    this.runningTasks.delete(task.id);\n    this.taskDependencies.delete(task.id);\n    this.completedTasks.set(task.id, result);\n    \n    // Call callbacks\n    if (result.success) {\n      task.onSuccess?.(result.result!);\n    } else {\n      task.onError?.(result.error);\n    }\n    \n    task.onComplete?.();\n    \n    // Process next tasks\n    this.processQueue();\n  }\n  \n  private async executeWithTimeout\u003CT>(task: Task\u003CT>): Promise\u003CT> {\n    const timeout = task.timeout ?? this.options.defaultTimeout;\n    \n    if (timeout \u003C= 0) {\n      return task.execute();\n    }\n    \n    const timeoutPromise = new Promise\u003Cnever>((_, reject) => {\n      setTimeout(() => reject(new Error(`Task ${task.id} timeout`)), timeout);\n    });\n    \n    return Promise.race([task.execute(), timeoutPromise]);\n  }\n  \n  private sortTasks(): void {\n    this.pendingTasks.sort((a, b) => {\n      // Higher priority first\n      if (b.priority !== a.priority) {\n        return b.priority - a.priority;\n      }\n      \n      // If priorities are equal, maintain insertion order\n      return 0;\n    });\n  }\n  \n  private notifyQueueChange(): void {\n    this.options.onQueueChange?.(\n      this.pendingTasks.length,\n      this.runningTasks.size\n    );\n  }\n  \n  // Advanced: Task groups\n  addTaskGroup(\n    tasks: Array\u003COmit\u003CTask, 'id'>>,\n    options?: {\n      parallel?: boolean; // true: tasks can run in parallel, false: sequential\n      groupId?: string;\n    }\n  ): string[] {\n    const groupId = options?.groupId || `group_${++this.idCounter}`;\n    const taskIds: string[] = [];\n    \n    if (options?.parallel) {\n      // All tasks can run in parallel\n      taskIds.push(...this.addTasks(tasks));\n    } else {\n      // Tasks must run sequentially\n      for (let i = 0; i \u003C tasks.length; i++) {\n        const task = tasks[i];\n        const dependencies = i > 0 ? [taskIds[i - 1]] : undefined;\n        \n        const taskId = this.addTask({\n          ...task,\n          dependencies\n        });\n        \n        taskIds.push(taskId);\n      }\n    }\n    \n    return taskIds;\n  }\n  \n  // Advanced: Priority adjustment\n  adjustPriority(taskId: string, newPriority: number): boolean {\n    const pendingIndex = this.pendingTasks.findIndex(t => t.id === taskId);\n    \n    if (pendingIndex !== -1) {\n      this.pendingTasks[pendingIndex].priority = newPriority;\n      this.sortTasks();\n      return true;\n    }\n    \n    return false;\n  }\n}\n\n// Usage examples\n// Create scheduler with max 3 concurrent tasks\nconst scheduler = new PriorityScheduler({\n  maxConcurrent: 3,\n  defaultPriority: 0,\n  defaultTimeout: 10000,\n  onQueueChange: (pending, running) => {\n    console.log(`Queue: ${pending} pending, ${running} running`);\n  }\n});\n\n// Add tasks with different priorities\nconst task1Id = scheduler.addTask({\n  priority: 10, // High priority\n  execute: async () => {\n    console.log('Running high priority task');\n    await new Promise(resolve => setTimeout(resolve, 1000));\n    return 'Task 1 result';\n  },\n  onSuccess: (result) => console.log('Task 1 succeeded:', result)\n});\n\nconst task2Id = scheduler.addTask({\n  priority: 5, // Medium priority\n  execute: async () => {\n    console.log('Running medium priority task');\n    await new Promise(resolve => setTimeout(resolve, 2000));\n    return 'Task 2 result';\n  },\n  retries: 2 // Will retry twice on failure\n});\n\n// Task with dependencies\nconst task3Id = scheduler.addTask({\n  priority: 1,\n  execute: async () => {\n    console.log('Running dependent task');\n    return 'Task 3 result';\n  },\n  dependencies: [task1Id], // Must wait for task1 to complete\n  timeout: 5000\n});\n\n// Add multiple tasks\nconst taskIds = scheduler.addTasks([\n  {\n    priority: 2,\n    execute: async () => {\n      await new Promise(resolve => setTimeout(resolve, 500));\n      return 'Batch task 1';\n    }\n  },\n  {\n    priority: 3,\n    execute: async () => {\n      await new Promise(resolve => setTimeout(resolve, 300));\n      return 'Batch task 2';\n    }\n  }\n]);\n\n// Monitor task status\nconsole.log('Task 1 status:', scheduler.getTaskStatus(task1Id));\n\n// Wait for specific task\nscheduler.waitForTask(task1Id, 15000)\n  .then(result => console.log('Task 1 completed:', result))\n  .catch(error => console.error('Task 1 failed:', error));\n\n// Wait for all tasks\nscheduler.waitForAll(30000)\n  .then(results => {\n    console.log('All tasks completed');\n    console.log('Results:', results);\n  })\n  .catch(error => console.error('Timeout:', error));\n\n// Advanced: Task groups\nconst groupTaskIds = scheduler.addTaskGroup(\n  [\n    {\n      execute: async () => {\n        console.log('Group task 1');\n        return 'Group 1';\n      }\n    },\n    {\n      execute: async () => {\n        console.log('Group task 2');\n        return 'Group 2';\n      }\n    }\n  ],\n  { parallel: false } // Run sequentially\n);\n\n// Get statistics\nconst stats = scheduler.getStats();\nconsole.log('Scheduler stats:', stats);\n\n// Example: Image processing pipeline\nclass ImageProcessingScheduler {\n  private scheduler = new PriorityScheduler({\n    maxConcurrent: 2,\n    defaultPriority: 5\n  });\n  \n  processImage(imageId: string, operations: Array\u003C{\n    type: 'resize' | 'crop' | 'filter';\n    priority: number;\n  }>) {\n    const taskIds: string[] = [];\n    \n    for (let i = 0; i \u003C operations.length; i++) {\n      const operation = operations[i];\n      const dependencies = i > 0 ? [taskIds[i - 1]] : undefined;\n      \n      const taskId = this.scheduler.addTask({\n        id: `${imageId}_${operation.type}_${i}`,\n        priority: operation.priority,\n        dependencies,\n        execute: async () => {\n          console.log(`Processing ${imageId}: ${operation.type}`);\n          await new Promise(resolve => setTimeout(resolve, 1000));\n          return { imageId, operation: operation.type, success: true };\n        },\n        onError: (error) => {\n          console.error(`Failed to process ${imageId}:`, error);\n        }\n      });\n      \n      taskIds.push(taskId);\n    }\n    \n    return this.scheduler.waitForAll();\n  }\n}",{"id":606,"category":607,"title":608,"description":609,"author":9,"date":10,"tags":610,"code":614,"canPreview":488},"vue-use-fetch","vue","useFetch Composable","A simple data fetching composable with loading state and error handling",[611,612,613],"Vue3","Composables","Fetch","import { ref, type Ref } from 'vue';\n\ninterface UseFetchReturn\u003CT> {\n  data: Ref\u003CT | null>;\n  loading: Ref\u003Cboolean>;\n  error: Ref\u003CError | null>;\n  execute: () => Promise\u003Cvoid>;\n}\n\nexport function useFetch\u003CT>(url: string): UseFetchReturn\u003CT> {\n  const data = ref\u003CT | null>(null) as Ref\u003CT | null>;\n  const loading = ref(false);\n  const error = ref\u003CError | null>(null);\n\n  const execute = async () => {\n    loading.value = true;\n    error.value = null;\n    \n    try {\n      const response = await fetch(url);\n      if (!response.ok) {\n        throw new Error(`HTTP error! status: ${response.status}`);\n      }\n      data.value = await response.json();\n    } catch (e) {\n      error.value = e instanceof Error ? e : new Error('Unknown error');\n    } finally {\n      loading.value = false;\n    }\n  };\n\n  return { data, loading, error, execute };\n}\n\n// Usage example\n// const { data, loading, error, execute } = useFetch\u003CUser[]>('/api/users');\n// onMounted(() => execute());",{"id":616,"category":607,"title":617,"description":618,"author":9,"date":10,"tags":619,"code":621,"canPreview":488},"vue-use-debounce","useDebounce Composable","A composable for debouncing function calls with configurable delay",[611,612,620,486],"Debounce","import { ref, watch, type Ref } from 'vue';\n\ninterface UseDebounceOptions {\n  delay: number;\n  immediate?: boolean;\n}\n\nexport function useDebounce\u003CT>(value: Ref\u003CT>, options: UseDebounceOptions = { delay: 300, immediate: false }): Ref\u003CT> {\n  const debouncedValue = ref\u003CT>(value.value) as Ref\u003CT>;\n  let timeoutId: ReturnType\u003Ctypeof setTimeout> | null = null;\n\n  watch(value, (newVal) => {\n    if (options.immediate && timeoutId === null) {\n      debouncedValue.value = newVal;\n      return;\n    }\n\n    if (timeoutId) clearTimeout(timeoutId);\n    timeoutId = setTimeout(() => {\n      debouncedValue.value = newVal;\n    }, options.delay);\n  }, { immediate: options.immediate });\n\n  // Cleanup timeout on unmount\n  const cleanup = () => {\n    if (timeoutId) clearTimeout(timeoutId);\n  };\n\n  // Return debounced value and cleanup (optional)\n  return debouncedValue;\n}\n\n// Usage example\n// const searchQuery = ref('');\n// const debouncedSearch = useDebounce(searchQuery, { delay: 500 });\n// watch(debouncedSearch, (val) => { /* fetch search results */ });",{"id":623,"category":607,"title":624,"description":625,"author":9,"date":10,"tags":626,"code":629,"canPreview":488},"vue-use-storage","useStorage Composable","Reactive local/session storage with automatic serialization/deserialization",[611,612,627,628,541],"LocalStorage","SessionStorage","import { ref, watch, type Ref } from 'vue';\n\ntype StorageType = 'localStorage' | 'sessionStorage';\n\nexport function useStorage\u003CT>(\n  key: string,\n  initialValue: T,\n  storageType: StorageType = 'localStorage'\n): Ref\u003CT> {\n  // Get storage instance\n  const storage = window[storageType];\n\n  // Initialize with stored value or initial value\n  const storedValue = storage.getItem(key);\n  const value = ref\u003CT>(\n    storedValue ? JSON.parse(storedValue) : initialValue\n  ) as Ref\u003CT>;\n\n  // Sync changes to storage\n  watch(value, (newVal) => {\n    if (newVal === undefined) {\n      storage.removeItem(key);\n    } else {\n      storage.setItem(key, JSON.stringify(newVal));\n    }\n  }, { deep: true });\n\n  // Cleanup on unmount (optional)\n  const remove = () => {\n    storage.removeItem(key);\n    value.value = initialValue;\n  };\n\n  // Expose remove method via object if needed, or just return ref\n  return value;\n}\n\n// Usage example\n// const userSettings = useStorage('user-settings', { theme: 'light', notifications: true });\n// const sessionToken = useStorage('session-token', '', 'sessionStorage');",{"id":631,"category":607,"title":632,"description":633,"author":9,"date":10,"tags":634,"code":637,"canPreview":488},"vue-use-infinite-scroll","useInfiniteScroll Composable","Composable for infinite scroll functionality with intersection observer",[611,612,635,636,15],"InfiniteScroll","IntersectionObserver","import { ref, onMounted, onUnmounted, type Ref } from 'vue';\n\ninterface UseInfiniteScrollOptions {\n  root?: HTMLElement | null;\n  rootMargin?: string;\n  threshold?: number;\n  hasMore: Ref\u003Cboolean>;\n  loadMore: () => Promise\u003Cvoid>;\n}\n\nexport function useInfiniteScroll(\n  target: Ref\u003CHTMLElement | null>,\n  options: UseInfiniteScrollOptions\n) {\n  const loading = ref(false);\n  let observer: IntersectionObserver | null = null;\n\n  const handleIntersect = async ([entry]: IntersectionObserverEntry[]) => {\n    if (entry.isIntersecting && options.hasMore.value && !loading.value) {\n      loading.value = true;\n      try {\n        await options.loadMore();\n      } finally {\n        loading.value = false;\n      }\n    }\n  };\n\n  onMounted(() => {\n    if (!target.value || !IntersectionObserver) return;\n\n    observer = new IntersectionObserver(handleIntersect, {\n      root: options.root,\n      rootMargin: options.rootMargin || '200px',\n      threshold: options.threshold || 0\n    });\n\n    observer.observe(target.value);\n  });\n\n  onUnmounted(() => {\n    if (observer && target.value) {\n      observer.unobserve(target.value);\n      observer.disconnect();\n    }\n  });\n\n  return { loading };\n}\n\n// Usage example\n// const posts = ref([]);\n// const page = ref(1);\n// const hasMore = ref(true);\n// const loadMorePosts = async () => {\n//   const newPosts = await fetch(`/api/posts?page=${page.value}`).then(r => r.json());\n//   if (newPosts.length === 0) hasMore.value = false;\n//   posts.value.push(...newPosts);\n//   page.value++;\n// };\n// const loadMoreRef = ref\u003CHTMLElement | null>(null);\n// const { loading } = useInfiniteScroll(loadMoreRef, { hasMore, loadMore: loadMorePosts });",{"id":639,"category":607,"title":640,"description":641,"author":9,"date":10,"tags":642,"code":645,"canPreview":488},"vue-use-window-size","useWindowSize Composable","Reactive window size with debounced resize events",[611,612,643,644,541],"WindowSize","Responsive","import { ref, onMounted, onUnmounted } from 'vue';\n\ninterface WindowSize {\n  width: number;\n  height: number;\n  isMobile: boolean;\n  isTablet: boolean;\n  isDesktop: boolean;\n}\n\nexport function useWindowSize(debounceDelay = 100): WindowSize {\n  const width = ref(window.innerWidth);\n  const height = ref(window.innerHeight);\n  const isMobile = ref(width.value \u003C 768);\n  const isTablet = ref(width.value >= 768 && width.value \u003C 1024);\n  const isDesktop = ref(width.value >= 1024);\n\n  let resizeTimeout: ReturnType\u003Ctypeof setTimeout> | null = null;\n\n  const updateSize = () => {\n    width.value = window.innerWidth;\n    height.value = window.innerHeight;\n    isMobile.value = width.value \u003C 768;\n    isTablet.value = width.value >= 768 && width.value \u003C 1024;\n    isDesktop.value = width.value >= 1024;\n  };\n\n  const handleResize = () => {\n    if (resizeTimeout) clearTimeout(resizeTimeout);\n    resizeTimeout = setTimeout(updateSize, debounceDelay);\n  };\n\n  onMounted(() => {\n    window.addEventListener('resize', handleResize);\n    updateSize(); // Initial update\n  });\n\n  onUnmounted(() => {\n    window.removeEventListener('resize', handleResize);\n    if (resizeTimeout) clearTimeout(resizeTimeout);\n  });\n\n  return {\n    width: width.value,\n    height: height.value,\n    isMobile: isMobile.value,\n    isTablet: isTablet.value,\n    isDesktop: isDesktop.value\n  };\n}\n\n// Usage example\n// const { width, height, isMobile } = useWindowSize();\n// watch([width, height], () => { /* handle resize */ });",{"id":647,"category":607,"title":648,"description":649,"author":9,"date":10,"tags":650,"code":653,"canPreview":488},"vue-use-form-validation","useFormValidation Composable","Simple form validation composable with custom rules and error messages",[611,612,651,652],"FormValidation","Forms","import { ref, type Ref } from 'vue';\n\ntype ValidationRule\u003CT> = (value: T) => string | null;\ninterface FormErrors\u003CT> {\n  [K in keyof T]?: string;\n}\n\nexport function useFormValidation\u003CT extends Record\u003Cstring, any>>(\n  formData: Ref\u003CT>,\n  validationRules: { [K in keyof T]: ValidationRule\u003CT[K]> }\n) {\n  const errors = ref\u003CFormErrors\u003CT>>({}) as Ref\u003CFormErrors\u003CT>>;\n  const isValid = ref(false);\n\n  // Validate single field\n  const validateField = (field: keyof T) => {\n    const rule = validationRules[field];\n    if (!rule) return;\n    errors.value[field] = rule(formData.value[field]);\n  };\n\n  // Validate entire form\n  const validateForm = (): boolean => {\n    const formErrors: FormErrors\u003CT> = {};\n    \n    Object.keys(validationRules).forEach((field) => {\n      const key = field as keyof T;\n      const error = validationRules[key](formData.value[key]);\n      if (error) formErrors[key] = error;\n    });\n\n    errors.value = formErrors;\n    isValid.value = Object.keys(formErrors).length === 0;\n    return isValid.value;\n  };\n\n  // Reset errors\n  const resetErrors = () => {\n    errors.value = {};\n    isValid.value = false;\n  };\n\n  return {\n    errors,\n    isValid,\n    validateField,\n    validateForm,\n    resetErrors\n  };\n}\n\n// Usage example\n// const formData = ref({\n//   email: '',\n//   password: ''\n// });\n// const validationRules = {\n//   email: (val) => !val ? 'Email is required' : !/^\\S+@\\S+\\.\\S+$/.test(val) ? 'Invalid email' : null,\n//   password: (val) => !val ? 'Password is required' : val.length \u003C 6 ? 'Password must be at least 6 chars' : null\n// };\n// const { errors, validateForm } = useFormValidation(formData, validationRules);\n// const submit = () => {\n//   if (validateForm()) { /* submit form */ }\n// };",{"id":655,"category":607,"title":656,"description":657,"author":9,"date":10,"tags":658,"code":661,"canPreview":488},"vue-use-countdown","useCountdown Composable","Reactive countdown timer with start/pause/reset functionality",[611,612,659,660],"Countdown","Timer","import { ref, onUnmounted } from 'vue';\n\ninterface CountdownReturn {\n  seconds: Ref\u003Cnumber>;\n  minutes: Ref\u003Cnumber>;\n  hours: Ref\u003Cnumber>;\n  isRunning: Ref\u003Cboolean>;\n  start: () => void;\n  pause: () => void;\n  reset: (newDuration?: number) => void;\n}\n\nexport function useCountdown(initialDuration = 60): CountdownReturn {\n  const duration = ref(initialDuration);\n  const remainingTime = ref(initialDuration);\n  const isRunning = ref(false);\n  let intervalId: ReturnType\u003Ctypeof setInterval> | null = null;\n\n  // Calculate formatted time\n  const seconds = ref(remainingTime.value % 60);\n  const minutes = ref(Math.floor((remainingTime.value % 3600) / 60));\n  const hours = ref(Math.floor(remainingTime.value / 3600));\n\n  const updateFormattedTime = () => {\n    seconds.value = remainingTime.value % 60;\n    minutes.value = Math.floor((remainingTime.value % 3600) / 60);\n    hours.value = Math.floor(remainingTime.value / 3600);\n  };\n\n  const tick = () => {\n    if (remainingTime.value \u003C= 0) {\n      pause();\n      return;\n    }\n    remainingTime.value--;\n    updateFormattedTime();\n  };\n\n  const start = () => {\n    if (isRunning.value || remainingTime.value \u003C= 0) return;\n    isRunning.value = true;\n    intervalId = setInterval(tick, 1000);\n  };\n\n  const pause = () => {\n    if (!isRunning.value) return;\n    isRunning.value = false;\n    if (intervalId) clearInterval(intervalId);\n  };\n\n  const reset = (newDuration?: number) => {\n    pause();\n    duration.value = newDuration || initialDuration;\n    remainingTime.value = duration.value;\n    updateFormattedTime();\n  };\n\n  // Initial format\n  updateFormattedTime();\n\n  // Cleanup on unmount\n  onUnmounted(() => {\n    if (intervalId) clearInterval(intervalId);\n  });\n\n  return {\n    seconds,\n    minutes,\n    hours,\n    isRunning,\n    start,\n    pause,\n    reset\n  };\n}\n\n// Usage example\n// const { seconds, minutes, isRunning, start, pause, reset } = useCountdown(120);\n// start(); // Start countdown\n// pause(); // Pause countdown\n// reset(180); // Reset to 3 minutes",{"id":663,"category":607,"title":664,"description":665,"author":9,"date":10,"tags":666,"code":669,"canPreview":488},"vue-use-dark-mode","useDarkMode Composable","Reactive dark mode toggle with system preference detection and localStorage persistence",[611,612,667,668,541],"DarkMode","Theme","import { ref, watch, onMounted, onUnmounted } from 'vue';\n\ntype ThemeMode = 'light' | 'dark' | 'system';\n\nexport function useDarkMode(): {\n  isDark: Ref\u003Cboolean>;\n  themeMode: Ref\u003CThemeMode>;\n  toggleDarkMode: () => void;\n  setThemeMode: (mode: ThemeMode) => void;\n} {\n  // Get stored theme mode or default to system\n  const themeMode = ref\u003CThemeMode>(\n    (localStorage.getItem('theme-mode') as ThemeMode) || 'system'\n  );\n  const isDark = ref(false);\n  let mediaQuery: MediaQueryList | null = null;\n\n  // Update dark mode based on theme mode and system preference\n  const updateDarkMode = () => {\n    if (themeMode.value === 'system') {\n      isDark.value = window.matchMedia('(prefers-color-scheme: dark)').matches;\n    } else {\n      isDark.value = themeMode.value === 'dark';\n    }\n    \n    // Apply to document\n    document.documentElement.classList.toggle('dark', isDark.value);\n  };\n\n  // Toggle dark/light mode\n  const toggleDarkMode = () => {\n    setThemeMode(isDark.value ? 'light' : 'dark');\n  };\n\n  // Set specific theme mode\n  const setThemeMode = (mode: ThemeMode) => {\n    themeMode.value = mode;\n    localStorage.setItem('theme-mode', mode);\n    updateDarkMode();\n  };\n\n  // Listen to system preference changes\n  const handleSystemChange = () => {\n    if (themeMode.value === 'system') updateDarkMode();\n  };\n\n  onMounted(() => {\n    mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n    mediaQuery.addEventListener('change', handleSystemChange);\n    updateDarkMode();\n  });\n\n  onUnmounted(() => {\n    if (mediaQuery) {\n      mediaQuery.removeEventListener('change', handleSystemChange);\n    }\n  });\n\n  // Watch for theme mode changes\n  watch(themeMode, updateDarkMode);\n\n  return {\n    isDark,\n    themeMode,\n    toggleDarkMode,\n    setThemeMode\n  };\n}\n\n// Usage example\n// const { isDark, toggleDarkMode, setThemeMode } = useDarkMode();\n// toggleDarkMode(); // Switch between light/dark\n// setThemeMode('system'); // Use system preference",{"id":671,"category":607,"title":672,"description":673,"author":9,"date":10,"tags":674,"code":676,"canPreview":488},"vue-use-copy-to-clipboard","useCopyToClipboard Composable","Composable for copying text to clipboard with success/error states and fallback for older browsers",[611,612,675,15],"Clipboard","import { ref, type Ref } from 'vue';\n\nexport function useCopyToClipboard() {\n  const isCopied = ref(false);\n  const error = ref\u003CError | null>(null);\n  const copyTimeout: Ref\u003CReturnType\u003Ctypeof setTimeout> | null> = ref(null);\n\n  const copy = async (text: string): Promise\u003Cboolean> => {\n    try {\n      // Clear previous state\n      error.value = null;\n      if (copyTimeout.value) clearTimeout(copyTimeout.value);\n\n      // Use Clipboard API if available\n      if (navigator.clipboard) {\n        await navigator.clipboard.writeText(text);\n      } else {\n        // Fallback for older browsers\n        const textArea = document.createElement('textarea');\n        textArea.value = text;\n        textArea.style.position = 'fixed';\n        textArea.style.left = '-999999px';\n        textArea.style.top = '-999999px';\n        document.body.appendChild(textArea);\n        textArea.focus();\n        textArea.select();\n        document.execCommand('copy');\n        document.body.removeChild(textArea);\n      }\n\n      // Set copied state (auto-reset after 2s)\n      isCopied.value = true;\n      copyTimeout.value = setTimeout(() => {\n        isCopied.value = false;\n      }, 2000);\n\n      return true;\n    } catch (e) {\n      error.value = e instanceof Error ? e : new Error('Failed to copy text');\n      isCopied.value = false;\n      return false;\n    }\n  };\n\n  // Cleanup timeout on unmount\n  const cleanup = () => {\n    if (copyTimeout.value) clearTimeout(copyTimeout.value);\n  };\n\n  return {\n    isCopied,\n    error,\n    copy,\n    cleanup\n  };\n}\n\n// Usage example\n// const { isCopied, error, copy } = useCopyToClipboard();\n// const handleCopy = async () => {\n//   const success = await copy('Hello World!');\n//   if (success) console.log('Copied!');\n// };",{"id":678,"category":607,"title":679,"description":680,"author":9,"date":10,"tags":681,"code":683,"canPreview":488},"vue-use-task-queue","useTaskQueue Composable","Composable for managing sequential execution of async tasks with concurrency control",[611,612,549,682,603],"TaskQueue","import { ref, onUnmounted } from 'vue';\n\ntype Task\u003CT = void> = () => Promise\u003CT>;\n\ninterface TaskQueueReturn {\n  queue: Ref\u003CTask[]>;\n  isProcessing: Ref\u003Cboolean>;\n  pendingTasks: Ref\u003Cnumber>;\n  addTask: \u003CT>(task: Task\u003CT>) => Promise\u003CT>;\n  clearQueue: () => void;\n}\n\nexport function useTaskQueue(concurrency = 1): TaskQueueReturn {\n  const queue = ref\u003CTask[]>([]);\n  const isProcessing = ref(false);\n  const pendingTasks = ref(0);\n  let activeWorkers = 0;\n\n  const processQueue = async () => {\n    // Exit if no tasks or max concurrency reached\n    if (queue.value.length === 0 || activeWorkers >= concurrency) {\n      isProcessing.value = false;\n      return;\n    }\n\n    isProcessing.value = true;\n    activeWorkers++;\n    pendingTasks.value = queue.value.length;\n\n    // Get next task\n    const task = queue.value.shift();\n    if (!task) {\n      activeWorkers--;\n      pendingTasks.value = queue.value.length;\n      return processQueue();\n    }\n\n    try {\n      await task();\n    } catch (error) {\n      console.error('Task failed:', error);\n      // Re-throw to allow caller to handle\n      throw error;\n    } finally {\n      activeWorkers--;\n      pendingTasks.value = queue.value.length;\n      // Process next task\n      processQueue();\n    }\n  };\n\n  const addTask = async \u003CT>(task: Task\u003CT>): Promise\u003CT> => {\n    return new Promise((resolve, reject) => {\n      // Wrap task to handle resolve/reject\n      const wrappedTask = async () => {\n        try {\n          const result = await task();\n          resolve(result);\n          return result;\n        } catch (error) {\n          reject(error);\n          throw error;\n        }\n      };\n\n      queue.value.push(wrappedTask);\n      pendingTasks.value = queue.value.length;\n      processQueue();\n    });\n  };\n\n  const clearQueue = () => {\n    queue.value = [];\n    pendingTasks.value = 0;\n  };\n\n  onUnmounted(() => {\n    clearQueue();\n    isProcessing.value = false;\n    activeWorkers = 0;\n  });\n\n  return {\n    queue,\n    isProcessing,\n    pendingTasks,\n    addTask,\n    clearQueue\n  };\n}\n\n// Usage example\n// const { addTask, pendingTasks, isProcessing } = useTaskQueue(2);\n// \n// // Add tasks\n// const task1 = () => fetch('/api/data1').then(r => r.json());\n// const task2 = () => fetch('/api/data2').then(r => r.json());\n// const task3 = () => fetch('/api/data3').then(r => r.json());\n// \n// addTask(task1).then(data => console.log('Task 1 done:', data));\n// addTask(task2).then(data => console.log('Task 2 done:', data));\n// addTask(task3).then(data => console.log('Task 3 done:', data));",{"id":685,"category":607,"title":686,"description":687,"author":9,"date":10,"tags":688,"code":691,"canPreview":488},"vue-use-element-size","useElementSize Composable","Reactive element size monitoring using ResizeObserver with cleanup",[611,612,689,690,541],"ResizeObserver","ElementSize","import { ref, onMounted, onUnmounted, type Ref } from 'vue';\n\ninterface ElementSize {\n  width: Ref\u003Cnumber>;\n  height: Ref\u003Cnumber>;\n}\n\nexport function useElementSize(target: Ref\u003CHTMLElement | null>): ElementSize {\n  const width = ref(0);\n  const height = ref(0);\n  let observer: ResizeObserver | null = null;\n\n  const updateSize = (entries: ResizeObserverEntry[]) => {\n    const entry = entries[0];\n    if (entry) {\n      width.value = entry.contentRect.width;\n      height.value = entry.contentRect.height;\n    }\n  };\n\n  onMounted(() => {\n    if (!target.value || !ResizeObserver) return;\n\n    // Initialize with current size\n    width.value = target.value.offsetWidth;\n    height.value = target.value.offsetHeight;\n\n    // Create observer\n    observer = new ResizeObserver(updateSize);\n    observer.observe(target.value);\n  });\n\n  onUnmounted(() => {\n    if (observer && target.value) {\n      observer.unobserve(target.value);\n      observer.disconnect();\n    }\n  });\n\n  return { width, height };\n}\n\n// Usage example\n// const containerRef = ref\u003CHTMLElement | null>(null);\n// const { width, height } = useElementSize(containerRef);\n// watch([width, height], ([newWidth, newHeight]) => {\n//   console.log('Element size changed:', newWidth, newHeight);\n// });\n\n// Template: \u003Cdiv ref=\"containerRef\">Content\u003C/div>",{"id":693,"category":607,"title":694,"description":695,"author":9,"date":10,"tags":696,"code":700,"canPreview":488},"vue-use-click-outside","useClickOutside Composable","Detect clicks outside a target element with cleanup and event options",[611,612,697,698,699],"ClickOutside","DOM","Events","import { onMounted, onUnmounted, type Ref } from 'vue';\n\nexport function useClickOutside(\n  target: Ref\u003CHTMLElement | null>,\n  callback: (event: MouseEvent | TouchEvent) => void,\n  options: { capture?: boolean; passive?: boolean } = { capture: true, passive: true }\n) {\n  const handleClickOutside = (event: MouseEvent | TouchEvent) => {\n    if (!target.value) return;\n    if (!target.value.contains(event.target as Node)) {\n      callback(event);\n    }\n  };\n\n  onMounted(() => {\n    document.addEventListener('click', handleClickOutside, options);\n    document.addEventListener('touchstart', handleClickOutside, options);\n  });\n\n  onUnmounted(() => {\n    document.removeEventListener('click', handleClickOutside, options);\n    document.removeEventListener('touchstart', handleClickOutside, options);\n  });\n}\n\n// Usage example\n// const dropdownRef = ref\u003CHTMLElement | null>(null);\n// useClickOutside(dropdownRef, () => {\n//   isDropdownOpen.value = false;\n// });",{"id":702,"category":607,"title":703,"description":704,"author":9,"date":10,"tags":705,"code":707,"canPreview":488},"vue-use-media-query","useMediaQuery Composable","Reactive media query matching with automatic cleanup",[611,612,706,644,541],"MediaQuery","import { ref, onMounted, onUnmounted } from 'vue';\n\nexport function useMediaQuery(query: string) {\n  const matches = ref(false);\n  let mediaQueryList: MediaQueryList | null = null;\n\n  const updateMatches = () => {\n    if (mediaQueryList) {\n      matches.value = mediaQueryList.matches;\n    }\n  };\n\n  onMounted(() => {\n    mediaQueryList = window.matchMedia(query);\n    matches.value = mediaQueryList.matches;\n    mediaQueryList.addEventListener('change', updateMatches);\n  });\n\n  onUnmounted(() => {\n    if (mediaQueryList) {\n      mediaQueryList.removeEventListener('change', updateMatches);\n    }\n  });\n\n  return matches;\n}\n\n// Usage example\n// const isSmallScreen = useMediaQuery('(max-width: 768px)');\n// const isRetina = useMediaQuery('(min-resolution: 2dppx)');\n// watch(isSmallScreen, (val) => console.log('Small screen:', val));",{"id":709,"category":607,"title":710,"description":711,"author":9,"date":10,"tags":712,"code":715,"canPreview":488},"vue-use-async-data","useAsyncData Composable","Enhanced async data fetching with caching, retry and abort controller",[611,612,713,613,714],"AsyncData","Caching","import { ref, type Ref, onUnmounted } from 'vue';\n\ninterface UseAsyncDataOptions\u003CT> {\n  cache?: boolean;\n  cacheKey?: string;\n  retry?: number;\n  retryDelay?: number;\n  immediate?: boolean;\n}\n\nconst cache = new Map\u003Cstring, any>();\n\nexport function useAsyncData\u003CT>(\n  fetcher: (signal: AbortSignal) => Promise\u003CT>,\n  options: UseAsyncDataOptions\u003CT> = { cache: false, retry: 0, retryDelay: 1000, immediate: true }\n): {\n  data: Ref\u003CT | null>;\n  loading: Ref\u003Cboolean>;\n  error: Ref\u003CError | null>;\n  refresh: () => Promise\u003CT | null>;\n  abort: () => void;\n} {\n  const data = ref\u003CT | null>(null) as Ref\u003CT | null>;\n  const loading = ref(false);\n  const error = ref\u003CError | null>(null);\n  let abortController: AbortController | null = null;\n\n  const abort = () => {\n    if (abortController) {\n      abortController.abort();\n      abortController = null;\n    }\n    loading.value = false;\n  };\n\n  const refresh = async (attempt = 0): Promise\u003CT | null> => {\n    // Use cache if available\n    if (options.cache && options.cacheKey && cache.has(options.cacheKey)) {\n      data.value = cache.get(options.cacheKey);\n      return data.value;\n    }\n\n    abort();\n    abortController = new AbortController();\n    loading.value = true;\n    error.value = null;\n\n    try {\n      const result = await fetcher(abortController.signal);\n      data.value = result;\n      // Cache the result\n      if (options.cache && options.cacheKey) {\n        cache.set(options.cacheKey, result);\n      }\n      return result;\n    } catch (e) {\n      error.value = e instanceof Error ? e : new Error('Unknown error');\n      // Retry if needed\n      if (attempt \u003C options.retry!) {\n        await new Promise(resolve => setTimeout(resolve, options.retryDelay!));\n        return refresh(attempt + 1);\n      }\n      return null;\n    } finally {\n      loading.value = false;\n    }\n  };\n\n  // Immediate fetch\n  if (options.immediate) {\n    refresh();\n  }\n\n  // Cleanup on unmount\n  onUnmounted(() => {\n    abort();\n  });\n\n  return { data, loading, error, refresh, abort };\n}\n\n// Usage example\n// const { data, loading, error, refresh } = useAsyncData(\n//   (signal) => fetch('/api/data', { signal }).then(r => r.json()),\n//   { cache: true, cacheKey: 'api-data', retry: 2 }\n// );",{"id":717,"category":607,"title":718,"description":719,"author":9,"date":10,"tags":720,"code":722,"canPreview":488},"vue-use-ratelimit","useRateLimit Composable","Rate limit function calls with configurable interval and max calls",[611,612,721,486,699],"RateLimit","import { ref, onUnmounted } from 'vue';\n\nexport function useRateLimit(\n  fn: (...args: any[]) => void,\n  interval = 1000,\n  maxCalls = 1\n) {\n  const callTimes = ref\u003Cnumber[]>([]);\n  const isRateLimited = ref(false);\n  let cleanupTimer: ReturnType\u003Ctypeof setTimeout> | null = null;\n\n  const rateLimitedFn = (...args: any[]) => {\n    const now = Date.now();\n    // Filter out call times outside the interval\n    callTimes.value = callTimes.value.filter(time => now - time \u003C interval);\n\n    if (callTimes.value.length \u003C maxCalls) {\n      callTimes.value.push(now);\n      isRateLimited.value = false;\n      fn(...args);\n    } else {\n      isRateLimited.value = true;\n    }\n\n    // Clean up old call times after interval\n    if (cleanupTimer) clearTimeout(cleanupTimer);\n    cleanupTimer = setTimeout(() => {\n      callTimes.value = [];\n      isRateLimited.value = false;\n    }, interval);\n  };\n\n  const reset = () => {\n    callTimes.value = [];\n    isRateLimited.value = false;\n    if (cleanupTimer) clearTimeout(cleanupTimer);\n  };\n\n  onUnmounted(() => {\n    if (cleanupTimer) clearTimeout(cleanupTimer);\n  });\n\n  return { rateLimitedFn, isRateLimited, reset };\n}\n\n// Usage example\n// const submitForm = (data) => console.log('Submit:', data);\n// const { rateLimitedFn: rateLimitedSubmit, isRateLimited } = useRateLimit(submitForm, 5000, 1);\n// // Only allows 1 submit every 5 seconds\n// rateLimitedSubmit({ name: 'Test' });",{"id":724,"category":607,"title":725,"description":726,"author":9,"date":10,"tags":727,"code":729,"canPreview":488},"vue-use-scroll-position","useScrollPosition Composable","Reactive scroll position tracking with debounce and direction detection",[611,612,111,728,541],"Position","import { ref, onMounted, onUnmounted } from 'vue';\n\ninterface ScrollPosition {\n  x: Ref\u003Cnumber>;\n  y: Ref\u003Cnumber>;\n  directionX: Ref\u003C'left' | 'right' | 'none'>;\n  directionY: Ref\u003C'up' | 'down' | 'none'>;\n  isTop: Ref\u003Cboolean>;\n  isBottom: Ref\u003Cboolean>;\n}\n\nexport function useScrollPosition(\n  target: HTMLElement | Window = window,\n  debounceDelay = 16\n): ScrollPosition {\n  const x = ref(0);\n  const y = ref(0);\n  const directionX = ref\u003C'left' | 'right' | 'none'>('none');\n  const directionY = ref\u003C'up' | 'down' | 'none'>('none');\n  const isTop = ref(true);\n  const isBottom = ref(false);\n  let lastX = 0;\n  let lastY = 0;\n  let scrollTimeout: ReturnType\u003Ctypeof setTimeout> | null = null;\n\n  const updateScrollPosition = () => {\n    const newX = target === window ? window.scrollX : (target as HTMLElement).scrollLeft;\n    const newY = target === window ? window.scrollY : (target as HTMLElement).scrollTop;\n\n    // Update direction\n    directionX.value = newX > lastX ? 'right' : newX \u003C lastX ? 'left' : 'none';\n    directionY.value = newY > lastY ? 'down' : newY \u003C lastY ? 'up' : 'none';\n\n    // Update position\n    x.value = newX;\n    y.value = newY;\n\n    // Update top/bottom state\n    isTop.value = newY === 0;\n    if (target === window) {\n      isBottom.value = newY + window.innerHeight >= document.documentElement.scrollHeight;\n    } else {\n      const el = target as HTMLElement;\n      isBottom.value = newY + el.clientHeight >= el.scrollHeight;\n    }\n\n    // Update last positions\n    lastX = newX;\n    lastY = newY;\n  };\n\n  const handleScroll = () => {\n    if (scrollTimeout) clearTimeout(scrollTimeout);\n    scrollTimeout = setTimeout(updateScrollPosition, debounceDelay);\n  };\n\n  onMounted(() => {\n    target.addEventListener('scroll', handleScroll, { passive: true });\n    updateScrollPosition(); // Initial position\n  });\n\n  onUnmounted(() => {\n    target.removeEventListener('scroll', handleScroll);\n    if (scrollTimeout) clearTimeout(scrollTimeout);\n  });\n\n  return { x, y, directionX, directionY, isTop, isBottom };\n}\n\n// Usage example\n// const { y, directionY, isTop } = useScrollPosition();\n// watch(directionY, (dir) => {\n//   if (dir === 'down' && !isTop.value) {\n//     headerRef.value.classList.add('sticky');\n//   } else {\n//     headerRef.value.classList.remove('sticky');\n//   }\n// });",{"id":731,"category":607,"title":732,"description":733,"author":9,"date":10,"tags":734,"code":737,"canPreview":488},"vue-use-toast","useToast Composable","Toast notification system with positioning, auto-dismiss and custom styles",[611,612,735,736,15],"Toast","Notifications","import { ref, type Ref } from 'vue';\n\ntype ToastType = 'success' | 'error' | 'warning' | 'info';\ninterface Toast {\n  id: string;\n  message: string;\n  type: ToastType;\n  duration?: number;\n  position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center';\n}\n\nexport function useToast() {\n  const toasts = ref\u003CToast[]>([]) as Ref\u003CToast[]>;\n\n  const generateId = () => `toast-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\n  const showToast = (options: {\n    message: string;\n    type?: ToastType;\n    duration?: number;\n    position?: Toast['position'];\n  }) => {\n    const toast: Toast = {\n      id: generateId(),\n      message: options.message,\n      type: options.type || 'info',\n      duration: options.duration || 3000,\n      position: options.position || 'top-right'\n    };\n\n    toasts.value.push(toast);\n\n    // Auto dismiss\n    if (toast.duration && toast.duration > 0) {\n      setTimeout(() => {\n        removeToast(toast.id);\n      }, toast.duration);\n    }\n\n    return toast.id;\n  };\n\n  const removeToast = (id: string) => {\n    toasts.value = toasts.value.filter(toast => toast.id !== id);\n  };\n\n  const clearToasts = (position?: Toast['position']) => {\n    if (position) {\n      toasts.value = toasts.value.filter(toast => toast.position !== position);\n    } else {\n      toasts.value = [];\n    }\n  };\n\n  // Convenience methods\n  const success = (message: string, options?: Omit\u003CParameters\u003Ctypeof showToast>[0], 'message' | 'type'>) => \n    showToast({ message, type: 'success', ...options });\n  const error = (message: string, options?: Omit\u003CParameters\u003Ctypeof showToast>[0], 'message' | 'type'>) => \n    showToast({ message, type: 'error', ...options });\n  const warning = (message: string, options?: Omit\u003CParameters\u003Ctypeof showToast>[0], 'message' | 'type'>) => \n    showToast({ message, type: 'warning', ...options });\n  const info = (message: string, options?: Omit\u003CParameters\u003Ctypeof showToast>[0], 'message' | 'type'>) => \n    showToast({ message, type: 'info', ...options });\n\n  return {\n    toasts,\n    showToast,\n    removeToast,\n    clearToasts,\n    success,\n    error,\n    warning,\n    info\n  };\n}\n\n// Usage example\n// const { success, error, toasts } = useToast();\n// success('Operation completed!', { duration: 4000 });\n// error('Something went wrong!');",{"id":739,"category":607,"title":740,"description":741,"author":9,"date":10,"tags":742,"code":745,"canPreview":488},"vue-use-permissions","usePermissions Composable","Reactive browser permission checking with request functionality",[611,612,743,744,541],"Permissions","Browser","import { ref, watch, onMounted } from 'vue';\n\ntype PermissionName = 'camera' | 'microphone' | 'notifications' | 'geolocation' | 'clipboard-read' | 'clipboard-write';\ntype PermissionStatus = 'granted' | 'denied' | 'prompt' | 'unsupported';\n\nexport function usePermissions(permissionName: PermissionName) {\n  const status = ref\u003CPermissionStatus>('unsupported');\n  const isGranted = ref(false);\n  const isDenied = ref(false);\n  const isPrompt = ref(false);\n\n  // Update derived states\n  const updateDerivedStates = () => {\n    isGranted.value = status.value === 'granted';\n    isDenied.value = status.value === 'denied';\n    isPrompt.value = status.value === 'prompt';\n  };\n\n  // Check permission status\n  const checkPermission = async () => {\n    try {\n      if (!navigator.permissions) {\n        status.value = 'unsupported';\n        updateDerivedStates();\n        return;\n      }\n\n      const permissionStatus = await navigator.permissions.query({\n        name: permissionName as PermissionName\n      });\n\n      // Update initial status\n      status.value = permissionStatus.state as PermissionStatus;\n      updateDerivedStates();\n\n      // Listen for status changes\n      permissionStatus.addEventListener('change', () => {\n        status.value = permissionStatus.state as PermissionStatus;\n        updateDerivedStates();\n      });\n    } catch (error) {\n      console.error('Failed to check permission:', error);\n      status.value = 'unsupported';\n      updateDerivedStates();\n    }\n  };\n\n  // Request permission (for permissions that require direct request)\n  const requestPermission = async (): Promise\u003Cboolean> => {\n    try {\n      switch (permissionName) {\n        case 'camera':\n          await navigator.mediaDevices.getUserMedia({ video: true });\n          break;\n        case 'microphone':\n          await navigator.mediaDevices.getUserMedia({ audio: true });\n          break;\n        case 'notifications':\n          await Notification.requestPermission();\n          break;\n        case 'geolocation':\n          await new Promise((resolve, reject) => {\n            navigator.geolocation.getCurrentPosition(resolve, reject);\n          });\n          break;\n        default:\n          break;\n      }\n\n      // Re-check status after request\n      await checkPermission();\n      return isGranted.value;\n    } catch (error) {\n      console.error('Failed to request permission:', error);\n      await checkPermission();\n      return false;\n    }\n  };\n\n  // Initial check\n  onMounted(() => {\n    checkPermission();\n  });\n\n  // Watch for status changes\n  watch(status, updateDerivedStates);\n\n  return {\n    status,\n    isGranted,\n    isDenied,\n    isPrompt,\n    checkPermission,\n    requestPermission\n  };\n}\n\n// Usage example\n// const { isGranted, requestPermission } = usePermissions('notifications');\n// const enableNotifications = async () => {\n//   const granted = await requestPermission();\n//   if (granted) {\n//     new Notification('Notifications enabled!');\n//   }\n// };",{"id":747,"category":607,"title":748,"description":749,"author":9,"date":10,"tags":750,"code":753,"canPreview":488},"vue-use-drag-drop","useDragDrop Composable","Simple drag and drop functionality with reactive drop zone state",[611,612,751,752,698],"DragDrop","FileUpload","import { ref, onMounted, onUnmounted, type Ref } from 'vue';\n\nexport function useDragDrop(\n  target: Ref\u003CHTMLElement | null>,\n  onDrop: (files: File[]) => void\n) {\n  const isDraggingOver = ref(false);\n  const dragCounter = ref(0);\n\n  // Prevent default browser behavior\n  const handleDragEvents = (e: DragEvent) => {\n    e.preventDefault();\n    e.stopPropagation();\n  };\n\n  const handleDragEnter = (e: DragEvent) => {\n    handleDragEvents(e);\n    dragCounter.value++;\n    isDraggingOver.value = true;\n  };\n\n  const handleDragLeave = (e: DragEvent) => {\n    handleDragEvents(e);\n    dragCounter.value--;\n    if (dragCounter.value === 0) {\n      isDraggingOver.value = false;\n    }\n  };\n\n  const handleDrop = (e: DragEvent) => {\n    handleDragEvents(e);\n    dragCounter.value = 0;\n    isDraggingOver.value = false;\n\n    if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {\n      const files = Array.from(e.dataTransfer.files);\n      onDrop(files);\n    }\n  };\n\n  onMounted(() => {\n    if (!target.value) return;\n\n    const el = target.value;\n    el.addEventListener('dragenter', handleDragEnter);\n    el.addEventListener('dragover', handleDragEvents);\n    el.addEventListener('dragleave', handleDragLeave);\n    el.addEventListener('drop', handleDrop);\n  });\n\n  onUnmounted(() => {\n    if (!target.value) return;\n\n    const el = target.value;\n    el.removeEventListener('dragenter', handleDragEnter);\n    el.removeEventListener('dragover', handleDragEvents);\n    el.removeEventListener('dragleave', handleDragLeave);\n    el.removeEventListener('drop', handleDrop);\n  });\n\n  return { isDraggingOver };\n}\n\n// Usage example\n// const dropZoneRef = ref\u003CHTMLElement | null>(null);\n// const { isDraggingOver } = useDragDrop(dropZoneRef, (files) => {\n//   console.log('Dropped files:', files);\n//   // Handle file upload\n// });",{"id":755,"category":607,"title":756,"description":757,"author":9,"date":10,"tags":758,"code":760,"canPreview":488},"vue-use-interval","useInterval Composable","Reactive interval with start/pause/resume/reset functionality and cleanup",[611,612,759,660,541],"Interval","import { ref, onUnmounted, type Ref } from 'vue';\n\nexport function useInterval(\n  callback: () => void,\n  interval: Ref\u003Cnumber> | number = 1000,\n  autoStart = true\n) {\n  const isActive = ref(false);\n  const remainingTime = ref(0);\n  const lastStartTime = ref\u003Cnumber | null>(null);\n  let intervalId: ReturnType\u003Ctypeof setInterval> | null = null;\n  let timeoutId: ReturnType\u003Ctypeof setTimeout> | null = null;\n\n  // Get interval value (handle reactive ref)\n  const getInterval = () => typeof interval === 'number' ? interval : interval.value;\n\n  const start = () => {\n    if (isActive.value) return;\n\n    isActive.value = true;\n    lastStartTime.value = Date.now();\n    remainingTime.value = 0;\n\n    // Clear existing timers\n    if (intervalId) clearInterval(intervalId);\n    if (timeoutId) clearTimeout(timeoutId);\n\n    // Run callback immediately if needed\n    callback();\n\n    // Set interval\n    intervalId = setInterval(callback, getInterval());\n  };\n\n  const pause = () => {\n    if (!isActive.value) return;\n\n    isActive.value = false;\n    if (lastStartTime.value) {\n      const elapsed = Date.now() - lastStartTime.value;\n      remainingTime.value = getInterval() - elapsed;\n    }\n\n    // Clear timers\n    if (intervalId) clearInterval(intervalId);\n    if (timeoutId) clearTimeout(timeoutId);\n  };\n\n  const resume = () => {\n    if (isActive.value) return;\n\n    isActive.value = true;\n    lastStartTime.value = Date.now();\n\n    // Use remaining time if available\n    if (remainingTime.value > 0) {\n      timeoutId = setTimeout(() => {\n        callback();\n        intervalId = setInterval(callback, getInterval());\n        remainingTime.value = 0;\n      }, remainingTime.value);\n    } else {\n      start();\n    }\n  };\n\n  const reset = () => {\n    pause();\n    remainingTime.value = 0;\n    lastStartTime.value = null;\n  };\n\n  // Auto start\n  if (autoStart) {\n    start();\n  }\n\n  // Cleanup on unmount\n  onUnmounted(() => {\n    pause();\n    reset();\n  });\n\n  return {\n    isActive,\n    remainingTime,\n    start,\n    pause,\n    resume,\n    reset\n  };\n}\n\n// Usage example\n// const count = ref(0);\n// const { pause, resume, isActive } = useInterval(() => {\n//   count.value++;\n// }, 1000);\n// // Pause interval\n// pause();\n// // Resume interval\n// resume();",{"id":762,"category":607,"title":763,"description":764,"author":9,"date":10,"tags":765,"code":769,"canPreview":488},"vue-use-focus-trap","useFocusTrap Composable","Accessibility-focused focus trap for modals and dialogs with keyboard navigation",[611,612,766,767,768],"FocusTrap","Accessibility","a11y","import { ref, onMounted, onUnmounted, type Ref } from 'vue';\n\nexport function useFocusTrap(\n  container: Ref\u003CHTMLElement | null>,\n  active: Ref\u003Cboolean> = ref(true)\n) {\n  const focusableSelectors = [\n    'button:not([disabled])',\n    'a[href]:not([disabled])',\n    'input:not([disabled]):not([type=\"hidden\"])',\n    'select:not([disabled])',\n    'textarea:not([disabled])',\n    '[tabindex]:not([tabindex=\"-1\"]):not([disabled])',\n    '[contenteditable=\"true\"]:not([disabled])'\n  ].join(',');\n\n  let focusableElements: HTMLElement[] = [];\n  let firstElement: HTMLElement | null = null;\n  let lastElement: HTMLElement | null = null;\n  let lastFocusedElement: HTMLElement | null = null;\n\n  // Get focusable elements\n  const getFocusableElements = () => {\n    if (!container.value) return [];\n    return Array.from(container.value.querySelectorAll(focusableSelectors)) as HTMLElement[];\n  };\n\n  // Trap focus inside container\n  const trapFocus = (e: KeyboardEvent) => {\n    if (!active.value || !container.value) return;\n\n    // Only handle Tab key\n    if (e.key !== 'Tab') return;\n\n    focusableElements = getFocusableElements();\n    if (focusableElements.length === 0) return;\n\n    firstElement = focusableElements[0];\n    lastElement = focusableElements[focusableElements.length - 1];\n    const currentFocused = document.activeElement as HTMLElement;\n\n    // Reverse tab (Shift + Tab)\n    if (e.shiftKey && currentFocused === firstElement) {\n      e.preventDefault();\n      lastElement?.focus();\n    }\n    // Forward tab\n    else if (!e.shiftKey && currentFocused === lastElement) {\n      e.preventDefault();\n      firstElement?.focus();\n    }\n  };\n\n  // Activate focus trap\n  const activate = () => {\n    if (!container.value) return;\n\n    // Save last focused element\n    lastFocusedElement = document.activeElement as HTMLElement;\n\n    // Get focusable elements and focus first\n    focusableElements = getFocusableElements();\n    if (focusableElements.length > 0) {\n      focusableElements[0].focus();\n    }\n\n    // Add event listener\n    document.addEventListener('keydown', trapFocus);\n  };\n\n  // Deactivate focus trap\n  const deactivate = () => {\n    document.removeEventListener('keydown', trapFocus);\n    // Restore focus to last focused element\n    if (lastFocusedElement) {\n      lastFocusedElement.focus();\n    }\n  };\n\n  // Watch active state\n  const updateFocusTrap = () => {\n    if (active.value) {\n      activate();\n    } else {\n      deactivate();\n    }\n  };\n\n  onMounted(() => {\n    if (active.value) {\n      activate();\n    }\n    // Watch for active state changes (if reactive)\n    if (typeof active === 'object' && 'value' in active) {\n      const stopWatch = watch(active, updateFocusTrap);\n      onUnmounted(stopWatch);\n    }\n  });\n\n  onUnmounted(() => {\n    deactivate();\n  });\n\n  return { activate, deactivate };\n}\n\n// Usage example\n// const modalRef = ref\u003CHTMLElement | null>(null);\n// const isModalOpen = ref(false);\n// const { activate, deactivate } = useFocusTrap(modalRef, isModalOpen);\n// // Open modal\n// isModalOpen.value = true;\n// activate();\n// // Close modal\n// isModalOpen.value = false;\n// deactivate();",{"id":771,"category":607,"title":772,"description":773,"author":9,"date":10,"tags":774,"code":776,"canPreview":488},"vue-use-lazy-load","useLazyLoad Composable","Reactive lazy loading for images and components with IntersectionObserver",[611,612,775,636,486],"LazyLoad","import { ref, onMounted, onUnmounted, type Ref } from 'vue';\n\nexport function useLazyLoad(\n  target: Ref\u003CHTMLElement | null>,\n  options: IntersectionObserverInit = { rootMargin: '200px 0px' }\n) {\n  const isLoaded = ref(false);\n  const isIntersecting = ref(false);\n  let observer: IntersectionObserver | null = null;\n\n  const loadContent = () => {\n    if (isLoaded.value) return;\n    isLoaded.value = true;\n    // For images: set src from data-src\n    if (target.value?.tagName === 'IMG') {\n      const img = target.value as HTMLImageElement;\n      if (img.dataset.src) {\n        img.src = img.dataset.src;\n        img.removeAttribute('data-src');\n      }\n    }\n  };\n\n  const handleIntersect = ([entry]: IntersectionObserverEntry[]) => {\n    isIntersecting.value = entry.isIntersecting;\n    if (entry.isIntersecting) {\n      loadContent();\n      observer?.unobserve(entry.target);\n    }\n  };\n\n  onMounted(() => {\n    if (!target.value || !IntersectionObserver) {\n      loadContent();\n      return;\n    }\n\n    observer = new IntersectionObserver(handleIntersect, options);\n    observer.observe(target.value);\n  });\n\n  onUnmounted(() => {\n    if (observer && target.value) {\n      observer.unobserve(target.value);\n      observer.disconnect();\n    }\n  });\n\n  return { isLoaded, isIntersecting, loadContent };\n}\n\n// Usage example\n// const imgRef = ref\u003CHTMLImageElement | null>(null);\n// const { isLoaded } = useLazyLoad(imgRef);\n// Template: \u003Cimg ref=\"imgRef\" data-src=\"/large-image.jpg\" v-if=\"isLoaded\">",{"id":778,"category":607,"title":779,"description":780,"author":9,"date":10,"tags":781,"code":784,"canPreview":488},"vue-use-network-status","useNetworkStatus Composable","Reactive network status monitoring with offline/online detection and speed estimation",[611,612,782,783,541],"Network","OnlineStatus","import { ref, onMounted, onUnmounted } from 'vue';\n\ninterface NetworkStatus {\n  isOnline: Ref\u003Cboolean>;\n  downlink: Ref\u003Cnumber | null>;\n  effectiveType: Ref\u003C'slow-2g' | '2g' | '3g' | '4g' | null>;\n  rtt: Ref\u003Cnumber | null>;\n  saveData: Ref\u003Cboolean | null>;\n}\n\nexport function useNetworkStatus(): NetworkStatus {\n  const isOnline = ref(navigator.onLine);\n  const downlink = ref\u003Cnumber | null>(null);\n  const effectiveType = ref\u003C'slow-2g' | '2g' | '3g' | '4g' | null>(null);\n  const rtt = ref\u003Cnumber | null>(null);\n  const saveData = ref\u003Cboolean | null>(null);\n\n  const updateNetworkInfo = () => {\n    if (!navigator.connection) return;\n    const conn = navigator.connection as NetworkInformation;\n    downlink.value = conn.downlink;\n    effectiveType.value = conn.effectiveType as any;\n    rtt.value = conn.rtt;\n    saveData.value = conn.saveData;\n  };\n\n  const handleOnline = () => {\n    isOnline.value = true;\n    updateNetworkInfo();\n  };\n\n  const handleOffline = () => {\n    isOnline.value = false;\n  };\n\n  const handleConnectionChange = () => {\n    updateNetworkInfo();\n  };\n\n  onMounted(() => {\n    window.addEventListener('online', handleOnline);\n    window.addEventListener('offline', handleOffline);\n    if (navigator.connection) {\n      navigator.connection.addEventListener('change', handleConnectionChange);\n      updateNetworkInfo();\n    }\n  });\n\n  onUnmounted(() => {\n    window.removeEventListener('online', handleOnline);\n    window.removeEventListener('offline', handleOffline);\n    if (navigator.connection) {\n      navigator.connection.removeEventListener('change', handleConnectionChange);\n    }\n  });\n\n  return { isOnline, downlink, effectiveType, rtt, saveData };\n}\n\n// Usage example\n// const { isOnline, effectiveType } = useNetworkStatus();\n// watch(isOnline, (online) => {\n//   if (!online) showToast('You are offline!', { type: 'warning' });\n// });",{"id":786,"category":607,"title":787,"description":788,"author":9,"date":10,"tags":789,"code":792,"canPreview":488},"vue-use-sortable","useSortable Composable","Reactive array sorting with multiple sort criteria and direction control",[611,612,790,791,541],"Sorting","Arrays","import { ref, computed, type Ref } from 'vue';\n\ntype SortDirection = 'asc' | 'desc';\ntype SortKey\u003CT> = keyof T | ((item: T) => any);\n\ninterface SortConfig\u003CT> {\n  key: SortKey\u003CT>;\n  direction: SortDirection;\n}\n\nexport function useSortable\u003CT>(items: Ref\u003CT[]>) {\n  const sortConfig = ref\u003CSortConfig\u003CT> | null>(null);\n\n  // Get value from key or function\n  const getValue = (item: T, key: SortKey\u003CT>) => {\n    if (typeof key === 'function') {\n      return key(item);\n    }\n    return item[key];\n  };\n\n  // Sorted items computed property\n  const sortedItems = computed(() => {\n    if (!sortConfig.value || items.value.length === 0) {\n      return [...items.value];\n    }\n\n    const { key, direction } = sortConfig.value;\n    return [...items.value].sort((a, b) => {\n      const valueA = getValue(a, key);\n      const valueB = getValue(b, key);\n\n      // Handle different types\n      if (typeof valueA === 'string' && typeof valueB === 'string') {\n        return direction === 'asc' \n          ? valueA.localeCompare(valueB) \n          : valueB.localeCompare(valueA);\n      }\n      if (typeof valueA === 'number' && typeof valueB === 'number') {\n        return direction === 'asc' ? valueA - valueB : valueB - valueA;\n      }\n      if (valueA instanceof Date && valueB instanceof Date) {\n        return direction === 'asc' ? valueA.getTime() - valueB.getTime() : valueB.getTime() - valueA.getTime();\n      }\n      // Fallback for other types\n      return 0;\n    });\n  });\n\n  // Set sort configuration\n  const setSort = (key: SortKey\u003CT>, direction?: SortDirection) => {\n    // Toggle direction if same key\n    if (sortConfig.value?.key === key) {\n      sortConfig.value.direction = sortConfig.value.direction === 'asc' ? 'desc' : 'asc';\n    } else {\n      sortConfig.value = {\n        key,\n        direction: direction || 'asc'\n      };\n    }\n  };\n\n  // Reset sorting\n  const resetSort = () => {\n    sortConfig.value = null;\n  };\n\n  // Toggle sort direction for current key\n  const toggleSortDirection = () => {\n    if (sortConfig.value) {\n      sortConfig.value.direction = sortConfig.value.direction === 'asc' ? 'desc' : 'asc';\n    }\n  };\n\n  return {\n    sortedItems,\n    sortConfig,\n    setSort,\n    resetSort,\n    toggleSortDirection\n  };\n}\n\n// Usage example\n// const items = ref([{ name: 'Banana', price: 1.2 }, { name: 'Apple', price: 0.8 }]);\n// const { sortedItems, setSort } = useSortable(items);\n// setSort('name'); // Sort by name ascending\n// setSort('price', 'desc'); // Sort by price descending",{"id":794,"category":607,"title":795,"description":796,"author":9,"date":10,"tags":797,"code":799,"canPreview":488},"vue-use-modal","useModal Composable","Reusable modal management with keyboard navigation and backdrop click handling",[611,612,798,15,767],"Modal","import { ref, onMounted, onUnmounted, type Ref } from 'vue';\nimport { useFocusTrap } from './useFocusTrap'; // Reuse focus trap composable\n\nexport function useModal(\n  modalRef: Ref\u003CHTMLElement | null>,\n  backdropRef: Ref\u003CHTMLElement | null> = ref(null)\n) {\n  const isOpen = ref(false);\n  const { activate: activateFocusTrap, deactivate: deactivateFocusTrap } = useFocusTrap(modalRef, isOpen);\n\n  // Open modal\n  const open = () => {\n    if (isOpen.value) return;\n    isOpen.value = true;\n    document.body.style.overflow = 'hidden'; // Prevent body scroll\n    setTimeout(() => activateFocusTrap(), 0); // Wait for modal to render\n  };\n\n  // Close modal\n  const close = () => {\n    if (!isOpen.value) return;\n    isOpen.value = false;\n    document.body.style.overflow = ''; // Restore body scroll\n    deactivateFocusTrap();\n  };\n\n  // Toggle modal\n  const toggle = () => {\n    isOpen.value ? close() : open();\n  };\n\n  // Handle escape key\n  const handleEscapeKey = (e: KeyboardEvent) => {\n    if (e.key === 'Escape' && isOpen.value) {\n      close();\n    }\n  };\n\n  // Handle backdrop click\n  const handleBackdropClick = (e: MouseEvent) => {\n    if (backdropRef.value && e.target === backdropRef.value && isOpen.value) {\n      close();\n    }\n  };\n\n  onMounted(() => {\n    document.addEventListener('keydown', handleEscapeKey);\n    if (backdropRef.value) {\n      backdropRef.value.addEventListener('click', handleBackdropClick);\n    }\n  });\n\n  onUnmounted(() => {\n    document.removeEventListener('keydown', handleEscapeKey);\n    if (backdropRef.value) {\n      backdropRef.value.removeEventListener('click', handleBackdropClick);\n    }\n    // Cleanup\n    if (isOpen.value) {\n      document.body.style.overflow = '';\n    }\n  });\n\n  return {\n    isOpen,\n    open,\n    close,\n    toggle\n  };\n}\n\n// Usage example\n// const modalRef = ref\u003CHTMLElement | null>(null);\n// const backdropRef = ref\u003CHTMLElement | null>(null);\n// const { isOpen, open, close } = useModal(modalRef, backdropRef);\n// open(); // Open modal\n// close(); // Close modal",{"id":801,"category":607,"title":802,"description":803,"author":9,"date":10,"tags":804,"code":807,"canPreview":488},"vue-use-deep-watch","useDeepWatch Composable","Enhanced deep watch with debounce, immediate execution and cleanup",[611,612,805,541,806],"Watch","DeepWatch","import { watch, type Ref, type WatchSource, onUnmounted } from 'vue';\n\nexport function useDeepWatch\u003CT>(\n  source: WatchSource\u003CT> | WatchSource\u003CT>[],\n  callback: (newVal: T, oldVal: T) => void | Promise\u003Cvoid>,\n  options: {\n    deep?: boolean;\n    immediate?: boolean;\n    debounce?: number;\n    flush?: 'pre' | 'post' | 'sync';\n  } = { deep: true, immediate: false, debounce: 0 }\n) {\n  let debounceTimeout: ReturnType\u003Ctypeof setTimeout> | null = null;\n  let cleanupFn: (() => void) | null = null;\n\n  // Wrapped callback with debounce\n  const wrappedCallback = (newVal: T, oldVal: T) => {\n    if (options.debounce && options.debounce > 0) {\n      if (debounceTimeout) clearTimeout(debounceTimeout);\n      debounceTimeout = setTimeout(() => {\n        callback(newVal, oldVal);\n      }, options.debounce);\n    } else {\n      callback(newVal, oldVal);\n    }\n  };\n\n  // Create watcher\n  const stopWatch = watch(\n    source as any,\n    wrappedCallback,\n    {\n      deep: options.deep ?? true,\n      immediate: options.immediate ?? false,\n      flush: options.flush ?? 'pre'\n    }\n  );\n\n  // Cleanup function\n  const cleanup = () => {\n    stopWatch();\n    if (debounceTimeout) clearTimeout(debounceTimeout);\n    if (cleanupFn) cleanupFn();\n  };\n\n  // Register cleanup on unmount\n  onUnmounted(cleanup);\n\n  // Allow setting custom cleanup\n  const setCleanup = (fn: () => void) => {\n    cleanupFn = fn;\n  };\n\n  return {\n    stop: stopWatch,\n    cleanup,\n    setCleanup\n  };\n}\n\n// Usage example\n// const formData = ref({ name: '', address: { city: '', zip: '' } });\n// const { cleanup } = useDeepWatch(\n//   formData,\n//   (newVal, oldVal) => console.log('Form changed:', newVal),\n//   { debounce: 300, immediate: true }\n// );\n// cleanup(); // Manual cleanup",{"id":809,"category":607,"title":810,"description":811,"author":9,"date":10,"tags":812,"code":814,"canPreview":488},"vue-use-pagination","usePagination Composable","Reactive pagination logic with page size control and range calculation",[611,612,813,15,791],"Pagination","import { ref, computed, type Ref } from 'vue';\n\nexport function usePagination\u003CT>(\n  items: Ref\u003CT[]>,\n  options: {\n    initialPage?: number;\n    initialPageSize?: number;\n    maxPageNumbers?: number;\n  } = { initialPage: 1, initialPageSize: 10, maxPageNumbers: 5 }\n) {\n  const currentPage = ref(options.initialPage ?? 1);\n  const pageSize = ref(options.initialPageSize ?? 10);\n  const maxPageNumbers = ref(options.maxPageNumbers ?? 5);\n\n  // Total items count\n  const totalItems = computed(() => items.value.length);\n\n  // Total pages count\n  const totalPages = computed(() => {\n    return Math.ceil(totalItems.value / pageSize.value);\n  });\n\n  // Current page items\n  const paginatedItems = computed(() => {\n    const startIndex = (currentPage.value - 1) * pageSize.value;\n    const endIndex = startIndex + pageSize.value;\n    return items.value.slice(startIndex, endIndex);\n  });\n\n  // Page numbers to display (for pagination UI)\n  const pageNumbers = computed(() => {\n    const pages: number[] = [];\n    const total = totalPages.value;\n    const current = currentPage.value;\n    const max = maxPageNumbers.value;\n\n    if (total \u003C= max) {\n      // Show all pages\n      for (let i = 1; i \u003C= total; i++) {\n        pages.push(i);\n      }\n    } else {\n      // Calculate range around current page\n      const half = Math.floor(max / 2);\n      let start = Math.max(1, current - half);\n      let end = Math.min(total, current + half);\n\n      // Adjust if near start/end\n      if (end - start + 1 \u003C max) {\n        if (start === 1) {\n          end = Math.min(total, start + max - 1);\n        } else if (end === total) {\n          start = Math.max(1, end - max + 1);\n        }\n      }\n\n      for (let i = start; i \u003C= end; i++) {\n        pages.push(i);\n      }\n\n      // Add ellipsis markers\n      if (start > 1) {\n        pages.unshift(-1); // Ellipsis marker\n        pages.unshift(1);\n      }\n      if (end \u003C total) {\n        pages.push(-1); // Ellipsis marker\n        pages.push(total);\n      }\n    }\n\n    return pages;\n  });\n\n  // Navigation methods\n  const goToPage = (page: number) => {\n    if (page \u003C 1 || page > totalPages.value) return;\n    currentPage.value = page;\n  };\n\n  const nextPage = () => {\n    if (currentPage.value \u003C totalPages.value) {\n      currentPage.value++;\n    }\n  };\n\n  const prevPage = () => {\n    if (currentPage.value > 1) {\n      currentPage.value--;\n    }\n  };\n\n  const firstPage = () => {\n    currentPage.value = 1;\n  };\n\n  const lastPage = () => {\n    currentPage.value = totalPages.value;\n  };\n\n  const setPageSize = (size: number) => {\n    pageSize.value = size;\n    // Reset to first page when changing page size\n    currentPage.value = 1;\n  };\n\n  return {\n    currentPage,\n    pageSize,\n    totalItems,\n    totalPages,\n    paginatedItems,\n    pageNumbers,\n    goToPage,\n    nextPage,\n    prevPage,\n    firstPage,\n    lastPage,\n    setPageSize\n  };\n}\n\n// Usage example\n// const items = ref(Array.from({ length: 100 }, (_, i) => ({ id: i + 1 })));\n// const { paginatedItems, currentPage, goToPage, nextPage } = usePagination(items);",{"id":816,"category":607,"title":817,"description":818,"author":9,"date":10,"tags":819,"code":822,"canPreview":488},"vue-use-keyboard-shortcut","useKeyboardShortcut Composable","Reactive keyboard shortcut handling with modifier keys and scoped targets",[611,612,820,821,699],"Keyboard","Shortcuts","import { ref, onMounted, onUnmounted, type Ref } from 'vue';\n\ntype ModifierKey = 'ctrl' | 'shift' | 'alt' | 'meta';\ninterface ShortcutOptions {\n  modifiers?: ModifierKey[];\n  target?: HTMLElement | Window;\n  preventDefault?: boolean;\n  stopPropagation?: boolean;\n  scoped?: boolean; // Only trigger when target is focused\n}\n\nexport function useKeyboardShortcut(\n  key: string | string[],\n  callback: (e: KeyboardEvent) => void,\n  options: ShortcutOptions = { preventDefault: true, stopPropagation: false, scoped: false }\n) {\n  const isListening = ref(true);\n  const keys = Array.isArray(key) ? key : [key];\n  const target = options.target || window;\n\n  const isModifierKeyPressed = (e: KeyboardEvent, modifier: ModifierKey) => {\n    switch (modifier) {\n      case 'ctrl': return e.ctrlKey;\n      case 'shift': return e.shiftKey;\n      case 'alt': return e.altKey;\n      case 'meta': return e.metaKey;\n      default: return false;\n    }\n  };\n\n  const areModifiersPressed = (e: KeyboardEvent) => {\n    const requiredModifiers = options.modifiers || [];\n    if (requiredModifiers.length === 0) return true;\n\n    // Check all required modifiers are pressed\n    return requiredModifiers.every(mod => isModifierKeyPressed(e, mod));\n  };\n\n  const handleKeyDown = (e: KeyboardEvent) => {\n    if (!isListening.value) return;\n\n    // Scoped mode: only trigger if target is focused\n    if (options.scoped && target !== window) {\n      const focusedElement = document.activeElement;\n      if (!focusedElement || !target.contains(focusedElement)) return;\n    }\n\n    // Check if key matches\n    const keyMatches = keys.some(k => {\n      // Normalize key (case insensitive, handle special keys)\n      const normalizedKey = k.toLowerCase();\n      const eventKey = e.key.toLowerCase();\n      \n      // Handle special cases (e.g. 'enter' vs 'return')\n      if (normalizedKey === 'enter' && eventKey === 'return') return true;\n      if (normalizedKey === 'esc' && eventKey === 'escape') return true;\n      \n      return eventKey === normalizedKey;\n    });\n\n    if (keyMatches && areModifiersPressed(e)) {\n      if (options.preventDefault) e.preventDefault();\n      if (options.stopPropagation) e.stopPropagation();\n      callback(e);\n    }\n  };\n\n  const enable = () => {\n    isListening.value = true;\n  };\n\n  const disable = () => {\n    isListening.value = false;\n  };\n\n  const toggle = () => {\n    isListening.value = !isListening.value;\n  };\n\n  onMounted(() => {\n    target.addEventListener('keydown', handleKeyDown);\n  });\n\n  onUnmounted(() => {\n    target.removeEventListener('keydown', handleKeyDown);\n  });\n\n  return {\n    isListening,\n    enable,\n    disable,\n    toggle\n  };\n}\n\n// Usage example\n// const { disable } = useKeyboardShortcut(\n//   's',\n//   () => saveDocument(),\n//   { modifiers: ['ctrl'], preventDefault: true }\n// );\n// // Disable shortcut temporarily\n// disable();",{"id":824,"category":607,"title":825,"description":826,"author":9,"date":10,"tags":827,"code":829,"canPreview":488},"vue-use-clipboard-monitor","useClipboardMonitor Composable","Reactive clipboard monitoring with content change detection and permission checks",[611,612,675,828,541],"Monitoring","import { ref, onMounted, onUnmounted } from 'vue';\n\nexport function useClipboardMonitor(\n  interval = 1000,\n  stopOnChange = false\n) {\n  const clipboardContent = ref\u003Cstring | null>(null);\n  const isMonitoring = ref(false);\n  const hasPermission = ref(false);\n  const error = ref\u003CError | null>(null);\n  let intervalId: ReturnType\u003Ctypeof setInterval> | null = null;\n\n  // Check clipboard permission\n  const checkPermission = async () => {\n    try {\n      if (!navigator.permissions || !navigator.clipboard) {\n        hasPermission.value = false;\n        error.value = new Error('Clipboard API not supported');\n        return false;\n      }\n\n      const permission = await navigator.permissions.query({\n        name: 'clipboard-read' as PermissionName\n      });\n\n      hasPermission.value = permission.state === 'granted';\n      if (permission.state === 'prompt') {\n        // Request permission by reading clipboard\n        await readClipboard();\n      }\n      return hasPermission.value;\n    } catch (e) {\n      error.value = e instanceof Error ? e : new Error('Failed to check permission');\n      hasPermission.value = false;\n      return false;\n    }\n  };\n\n  // Read clipboard content\n  const readClipboard = async () => {\n    try {\n      const content = await navigator.clipboard.readText();\n      // Check if content changed\n      if (content !== clipboardContent.value) {\n        clipboardContent.value = content;\n        if (stopOnChange) {\n          stopMonitoring();\n        }\n      }\n      error.value = null;\n      return content;\n    } catch (e) {\n      error.value = e instanceof Error ? e : new Error('Failed to read clipboard');\n      return null;\n    }\n  };\n\n  // Start monitoring\n  const startMonitoring = async () => {\n    if (isMonitoring.value) return;\n\n    const permissionGranted = await checkPermission();\n    if (!permissionGranted) return;\n\n    isMonitoring.value = true;\n    // Initial read\n    await readClipboard();\n    // Set up interval\n    intervalId = setInterval(readClipboard, interval);\n  };\n\n  // Stop monitoring\n  const stopMonitoring = () => {\n    isMonitoring.value = false;\n    if (intervalId) {\n      clearInterval(intervalId);\n      intervalId = null;\n    }\n  };\n\n  // Toggle monitoring\n  const toggleMonitoring = async () => {\n    if (isMonitoring.value) {\n      stopMonitoring();\n    } else {\n      await startMonitoring();\n    }\n  };\n\n  // Cleanup\n  onUnmounted(() => {\n    stopMonitoring();\n  });\n\n  return {\n    clipboardContent,\n    isMonitoring,\n    hasPermission,\n    error,\n    startMonitoring,\n    stopMonitoring,\n    toggleMonitoring,\n    readClipboard\n  };\n}\n\n// Usage example\n// const { clipboardContent, startMonitoring } = useClipboardMonitor(500);\n// startMonitoring();\n// watch(clipboardContent, (content) => {\n//   if (content) console.log('Clipboard changed:', content);\n// });",{"id":831,"category":607,"title":832,"description":833,"author":9,"date":10,"tags":834,"code":836,"canPreview":488},"vue-use-form-wizard","useFormWizard Composable","Multi-step form wizard management with validation and step navigation",[611,612,652,835,495],"Wizard","import { ref, computed, type Ref } from 'vue';\n\ntype StepValidator = () => boolean | Promise\u003Cboolean>;\n\ninterface WizardStep {\n  id: string | number;\n  label?: string;\n  validator?: StepValidator;\n  isDisabled?: boolean;\n}\n\nexport function useFormWizard(initialSteps: WizardStep[], initialStep = 0) {\n  const steps = ref\u003CWizardStep[]>(initialSteps);\n  const currentStepIndex = ref(Math.max(0, Math.min(initialStep, steps.value.length - 1)));\n  const isSubmitting = ref(false);\n  const stepErrors = ref\u003CRecord\u003Cstring | number, string | null>>({});\n\n  // Current step\n  const currentStep = computed(() => {\n    return steps.value[currentStepIndex.value];\n  });\n\n  // Navigation state\n  const canGoNext = computed(() => {\n    return currentStepIndex.value \u003C steps.value.length - 1 && \n           !steps.value[currentStepIndex.value + 1]?.isDisabled;\n  });\n\n  const canGoPrev = computed(() => {\n    return currentStepIndex.value > 0 && \n           !steps.value[currentStepIndex.value - 1]?.isDisabled;\n  });\n\n  const isFirstStep = computed(() => currentStepIndex.value === 0);\n  const isLastStep = computed(() => currentStepIndex.value === steps.value.length - 1);\n\n  // Validate current step\n  const validateCurrentStep = async (): Promise\u003Cboolean> => {\n    const step = currentStep.value;\n    if (!step.validator) return true;\n\n    try {\n      const isValid = await step.validator();\n      stepErrors.value[step.id] = isValid ? null : 'Step validation failed';\n      return isValid;\n    } catch (error) {\n      stepErrors.value[step.id] = error instanceof Error ? error.message : 'Validation error';\n      return false;\n    }\n  };\n\n  // Navigate to step\n  const goToStep = async (index: number): Promise\u003Cboolean> => {\n    if (\n      index \u003C 0 || \n      index >= steps.value.length || \n      steps.value[index]?.isDisabled ||\n      index === currentStepIndex.value\n    ) {\n      return false;\n    }\n\n    // Validate current step if moving forward\n    if (index > currentStepIndex.value) {\n      const isValid = await validateCurrentStep();\n      if (!isValid) return false;\n    }\n\n    currentStepIndex.value = index;\n    return true;\n  };\n\n  // Next step\n  const goToNextStep = async (): Promise\u003Cboolean> => {\n    if (!canGoNext.value) return false;\n    return goToStep(currentStepIndex.value + 1);\n  };\n\n  // Previous step\n  const goToPrevStep = async (): Promise\u003Cboolean> => {\n    if (!canGoPrev.value) return false;\n    return goToStep(currentStepIndex.value - 1);\n  };\n\n  // Reset wizard\n  const reset = (newSteps?: WizardStep[]) => {\n    if (newSteps) steps.value = newSteps;\n    currentStepIndex.value = 0;\n    stepErrors.value = {};\n    isSubmitting.value = false;\n  };\n\n  // Submit wizard (validate all steps)\n  const submit = async (onSubmit: () => void | Promise\u003Cvoid>): Promise\u003Cboolean> => {\n    if (isSubmitting.value) return false;\n\n    isSubmitting.value = true;\n    try {\n      // Validate all steps\n      for (let i = 0; i \u003C steps.value.length; i++) {\n        currentStepIndex.value = i;\n        const isValid = await validateCurrentStep();\n        if (!isValid) {\n          currentStepIndex.value = i;\n          return false;\n        }\n      }\n\n      // Run submit handler\n      await onSubmit();\n      return true;\n    } finally {\n      isSubmitting.value = false;\n    }\n  };\n\n  return {\n    steps,\n    currentStep,\n    currentStepIndex,\n    canGoNext,\n    canGoPrev,\n    isFirstStep,\n    isLastStep,\n    isSubmitting,\n    stepErrors,\n    validateCurrentStep,\n    goToStep,\n    goToNextStep,\n    goToPrevStep,\n    reset,\n    submit\n  };\n}\n\n// Usage example\n// const steps = [\n//   { id: 1, label: 'Personal Info', validator: validateStep1 },\n//   { id: 2, label: 'Billing Info', validator: validateStep2 },\n//   { id: 3, label: 'Review', validator: validateStep3 }\n// ];\n// const { currentStep, goToNextStep, submit } = useFormWizard(steps);\n// submit(() => console.log('Form submitted!'));",{"id":838,"category":607,"title":839,"description":840,"author":9,"date":10,"tags":841,"code":844,"canPreview":488},"vue-use-geo-location","useGeoLocation Composable","Reactive geolocation tracking with watch position and error handling",[611,612,842,843,541],"Geolocation","Maps","import { ref, onUnmounted, type Ref } from 'vue';\n\ninterface GeoLocation {\n  latitude: Ref\u003Cnumber | null>;\n  longitude: Ref\u003Cnumber | null>;\n  accuracy: Ref\u003Cnumber | null>;\n  altitude: Ref\u003Cnumber | null>;\n  altitudeAccuracy: Ref\u003Cnumber | null>;\n  heading: Ref\u003Cnumber | null>;\n  speed: Ref\u003Cnumber | null>;\n  timestamp: Ref\u003Cnumber | null>;\n  isLoading: Ref\u003Cboolean>;\n  error: Ref\u003CGeolocationPositionError | null>;\n  isWatching: Ref\u003Cboolean>;\n}\n\nexport function useGeoLocation(\n  options: PositionOptions = { enableHighAccuracy: false, timeout: 10000, maximumAge: 30000 }\n): GeoLocation {\n  const latitude = ref\u003Cnumber | null>(null);\n  const longitude = ref\u003Cnumber | null>(null);\n  const accuracy = ref\u003Cnumber | null>(null);\n  const altitude = ref\u003Cnumber | null>(null);\n  const altitudeAccuracy = ref\u003Cnumber | null>(null);\n  const heading = ref\u003Cnumber | null>(null);\n  const speed = ref\u003Cnumber | null>(null);\n  const timestamp = ref\u003Cnumber | null>(null);\n  const isLoading = ref(false);\n  const error = ref\u003CGeolocationPositionError | null>(null);\n  const isWatching = ref(false);\n  let watchId: number | null = null;\n\n  // Update position data\n  const updatePosition = (pos: GeolocationPosition) => {\n    const coords = pos.coords;\n    latitude.value = coords.latitude;\n    longitude.value = coords.longitude;\n    accuracy.value = coords.accuracy;\n    altitude.value = coords.altitude;\n    altitudeAccuracy.value = coords.altitudeAccuracy;\n    heading.value = coords.heading;\n    speed.value = coords.speed;\n    timestamp.value = pos.timestamp;\n    isLoading.value = false;\n    error.value = null;\n  };\n\n  // Handle position error\n  const handleError = (err: GeolocationPositionError) => {\n    error.value = err;\n    isLoading.value = false;\n    isWatching.value = false;\n  };\n\n  // Get current position once\n  const getCurrentPosition = async () => {\n    if (!navigator.geolocation) {\n      error.value = new Error('Geolocation is not supported by your browser') as GeolocationPositionError;\n      return;\n    }\n\n    isLoading.value = true;\n    try {\n      const pos = await new Promise\u003CGeolocationPosition>((resolve, reject) => {\n        navigator.geolocation.getCurrentPosition(resolve, reject, options);\n      });\n      updatePosition(pos);\n    } catch (err) {\n      handleError(err as GeolocationPositionError);\n    }\n  };\n\n  // Watch position changes\n  const watchPosition = () => {\n    if (!navigator.geolocation || isWatching.value) return;\n\n    isWatching.value = true;\n    isLoading.value = true;\n    watchId = navigator.geolocation.watchPosition(\n      updatePosition,\n      handleError,\n      options\n    );\n  };\n\n  // Clear watch\n  const clearWatch = () => {\n    if (watchId !== null && navigator.geolocation) {\n      navigator.geolocation.clearWatch(watchId);\n      watchId = null;\n    }\n    isWatching.value = false;\n  };\n\n  // Toggle watch position\n  const toggleWatch = () => {\n    if (isWatching.value) {\n      clearWatch();\n    } else {\n      watchPosition();\n    }\n  };\n\n  // Cleanup\n  onUnmounted(() => {\n    clearWatch();\n  });\n\n  return {\n    latitude,\n    longitude,\n    accuracy,\n    altitude,\n    altitudeAccuracy,\n    heading,\n    speed,\n    timestamp,\n    isLoading,\n    error,\n    isWatching,\n    getCurrentPosition,\n    watchPosition,\n    clearWatch,\n    toggleWatch\n  };\n}\n\n// Usage example\n// const { latitude, longitude, getCurrentPosition } = useGeoLocation();\n// getCurrentPosition().then(() => {\n//   console.log('Location:', latitude.value, longitude.value);\n// });",{"id":846,"category":847,"title":848,"description":849,"author":9,"date":10,"tags":850,"code":853,"canPreview":488},"react-use-debounce","react","useDebounce Hook","A custom React Hook for debouncing values and functions with TypeScript support",[851,852,620,486],"React","Hooks","import { useState, useEffect } from 'react';\n\nfunction useDebounce\u003CT>(value: T, delay = 500): T {\n  const [debouncedValue, setDebouncedValue] = useState\u003CT>(value);\n\n  useEffect(() => {\n    const timer = setTimeout(() => {\n      setDebouncedValue(value);\n    }, delay);\n\n    return () => {\n      clearTimeout(timer);\n    };\n  }, [value, delay]);\n\n  return debouncedValue;\n}\n\n// Usage example\n// const [searchTerm, setSearchTerm] = useState('');\n// const debouncedSearchTerm = useDebounce(searchTerm, 300);\n// useEffect(() => {\n//   if (debouncedSearchTerm) fetchData(debouncedSearchTerm);\n// }, [debouncedSearchTerm]);",{"id":855,"category":847,"title":856,"description":857,"author":9,"date":10,"tags":858,"code":859,"canPreview":488},"react-use-click-outside","useClickOutside Hook","A custom React Hook to detect clicks outside a component (e.g. modals/dropdowns) with TypeScript support",[851,852,698,15],"import { useEffect, RefObject } from 'react';\n\ntype Handler = (event: MouseEvent | TouchEvent) => void;\n\nfunction useClickOutside\u003CT extends HTMLElement = HTMLElement>(\n  ref: RefObject\u003CT>,\n  handler: Handler,\n  listenCapturing = true\n): void {\n  useEffect(() => {\n    const listener = (event: MouseEvent | TouchEvent) => {\n      const el = ref?.current;\n      if (!el || el.contains(event.target as Node)) {\n        return;\n      }\n      handler(event);\n    };\n\n    document.addEventListener('click', listener, listenCapturing);\n    document.addEventListener('touchstart', listener, listenCapturing);\n\n    return () => {\n      document.removeEventListener('click', listener, listenCapturing);\n      document.removeEventListener('touchstart', listener, listenCapturing);\n    };\n  }, [ref, handler, listenCapturing]);\n}\n\n// Usage example\n// const modalRef = useRef\u003CHTMLDivElement>(null);\n// useClickOutside(modalRef, () => setIsModalOpen(false));",{"id":861,"category":847,"title":862,"description":863,"author":9,"date":10,"tags":864,"code":866,"canPreview":488},"react-use-fetch","useFetch Hook","A custom React Hook for handling API requests with loading/error states and TypeScript support",[851,852,613,865,549],"API","import { useState, useEffect, useCallback } from 'react';\n\ntype FetchState\u003CT> = {\n  data: T | null;\n  loading: boolean;\n  error: Error | null;\n};\n\nfunction useFetch\u003CT>(url: string, options?: RequestInit): FetchState\u003CT> & { refetch: () => void } {\n  const [state, setState] = useState\u003CFetchState\u003CT>>({\n    data: null,\n    loading: true,\n    error: null\n  });\n\n  const fetchData = useCallback(async () => {\n    setState(prev => ({ ...prev, loading: true }));\n    try {\n      const response = await fetch(url, options);\n      if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);\n      const data = await response.json() as T;\n      setState({ data, loading: false, error: null });\n    } catch (error) {\n      setState({ data: null, loading: false, error: error as Error });\n    }\n  }, [url, options]);\n\n  useEffect(() => {\n    fetchData();\n  }, [fetchData]);\n\n  return { ...state, refetch: fetchData };\n}\n\n// Usage example\n// type User = { id: number; name: string };\n// const { data: users, loading, error, refetch } = useFetch\u003CUser[]>('/api/users');",{"id":868,"category":847,"title":869,"description":870,"author":9,"date":10,"tags":871,"code":872,"canPreview":488},"react-use-form","useForm Hook","A lightweight custom React Hook for form state management with validation and TypeScript support",[851,852,652,495],"import { useState, ChangeEvent } from 'react';\n\ntype ValidationRules\u003CT> = {\n  [K in keyof T]?: (value: T[K]) => string | null;\n};\n\ntype FormErrors\u003CT> = { [K in keyof T]?: string };\n\nfunction useForm\u003CT>(\n  initialValues: T,\n  validationRules?: ValidationRules\u003CT>\n) {\n  const [values, setValues] = useState\u003CT>(initialValues);\n  const [errors, setErrors] = useState\u003CFormErrors\u003CT>>({});\n\n  const handleChange = (e: ChangeEvent\u003CHTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {\n    const { name, value } = e.target;\n    setValues(prev => ({ ...prev, [name]: value }));\n  };\n\n  const validate = (): boolean => {\n    if (!validationRules) return true;\n    const newErrors: FormErrors\u003CT> = {};\n    Object.entries(validationRules).forEach(([key, rule]) => {\n      if (rule) {\n        const error = rule(values[key as keyof T]);\n        if (error) newErrors[key as keyof T] = error;\n      }\n    });\n    setErrors(newErrors);\n    return Object.keys(newErrors).length === 0;\n  };\n\n  const reset = () => setValues(initialValues);\n\n  return { values, errors, handleChange, validate, reset };\n}\n\n// Usage example\n// const { values, errors, handleChange, validate, reset } = useForm({\n//   email: '',\n//   password: ''\n// }, {\n//   email: (val) => !val ? 'Email is required' : !/^\\S+@\\S+\\.\\S+$/.test(val) ? 'Invalid email' : null,\n//   password: (val) => !val ? 'Password is required' : val.length \u003C 6 ? 'Min 6 chars' : null\n// });",{"id":874,"category":847,"title":875,"description":876,"author":9,"date":10,"tags":877,"code":878,"canPreview":488},"react-use-intersection-observer","useIntersectionObserver Hook","A custom React Hook for detecting element visibility with Intersection Observer API and TypeScript support",[851,852,636,486,775],"import { useState, useEffect, RefObject } from 'react';\n\ntype IntersectionObserverOptions = {\n  root?: Element | null;\n  rootMargin?: string;\n  threshold?: number | number[];\n};\n\nfunction useIntersectionObserver\u003CT extends HTMLElement>(\n  ref: RefObject\u003CT>,\n  options: IntersectionObserverOptions = {}\n): IntersectionObserverEntry | null {\n  const [entry, setEntry] = useState\u003CIntersectionObserverEntry | null>(null);\n\n  useEffect(() => {\n    const element = ref.current;\n    const observer = new IntersectionObserver(([entry]) => {\n      setEntry(entry);\n    }, options);\n\n    if (element) observer.observe(element);\n\n    return () => {\n      if (element) observer.unobserve(element);\n    };\n  }, [ref, options]);\n\n  return entry;\n}\n\n// Usage example\n// const imgRef = useRef\u003CHTMLImageElement>(null);\n// const entry = useIntersectionObserver(imgRef, { threshold: 0.1 });\n// const isVisible = entry?.isIntersecting;\n// useEffect(() => {\n//   if (isVisible) imgRef.current.src = imgRef.current.dataset.src;\n// }, [isVisible]);",{"id":880,"category":847,"title":881,"description":882,"author":9,"date":10,"tags":883,"code":884,"canPreview":488},"react-use-media-query","useMediaQuery Hook","A custom React Hook for detecting media query matches (responsive design) with TypeScript support",[851,852,706,644],"import { useState, useEffect } from 'react';\n\nfunction useMediaQuery(query: string): boolean {\n  const [matches, setMatches] = useState(false);\n\n  useEffect(() => {\n    const mediaQuery = window.matchMedia(query);\n    const handleChange = (e: MediaQueryListEvent) => setMatches(e.matches);\n\n    setMatches(mediaQuery.matches);\n    mediaQuery.addEventListener('change', handleChange);\n\n    return () => {\n      mediaQuery.removeEventListener('change', handleChange);\n    };\n  }, [query]);\n\n  return matches;\n}\n\n// Usage example\n// const isMobile = useMediaQuery('(max-width: 768px)');\n// const isTablet = useMediaQuery('(min-width: 769px) and (max-width: 1024px)');\n// const isDarkMode = useMediaQuery('(prefers-color-scheme: dark)');",{"id":886,"category":847,"title":887,"description":888,"author":9,"date":10,"tags":889,"code":891,"canPreview":488},"react-use-previous","usePrevious Hook","A custom React Hook to get the previous value of a state/prop with TypeScript support",[851,852,890,563],"State","import { useRef, useEffect } from 'react';\n\nfunction usePrevious\u003CT>(value: T): T | undefined {\n  const ref = useRef\u003CT>();\n\n  useEffect(() => {\n    ref.current = value;\n  }, [value]);\n\n  return ref.current;\n}\n\n// Usage example\n// const [count, setCount] = useState(0);\n// const prevCount = usePrevious(count);\n// console.log('Current:', count, 'Previous:', prevCount);\n\n// Advanced usage - compare changes\n// const [user, setUser] = useState({ name: 'John', age: 30 });\n// const prevUser = usePrevious(user);\n// useEffect(() => {\n//   if (prevUser?.age !== user.age) {\n//     console.log('Age changed!');\n//   }\n// }, [user, prevUser]);",{"id":893,"category":847,"title":894,"description":895,"author":9,"date":10,"tags":896,"code":898,"canPreview":488},"react-use-timeout","useTimeout Hook","A custom React Hook for managing setTimeout with cleanup and re-render support (TypeScript)",[851,852,897,563],"Timeout","import { useCallback, useEffect, useRef } from 'react';\n\nfunction useTimeout(\n  callback: () => void,\n  delay: number | null\n): () => void {\n  const callbackRef = useRef(callback);\n  const timeoutRef = useRef\u003CNodeJS.Timeout | null>(null);\n\n  // Update callback ref on each render\n  useEffect(() => {\n    callbackRef.current = callback;\n  }, [callback]);\n\n  // Set up timeout\n  useEffect(() => {\n    if (delay === null) return;\n\n    timeoutRef.current = setTimeout(() => callbackRef.current(), delay);\n\n    return () => {\n      if (timeoutRef.current) clearTimeout(timeoutRef.current);\n    };\n  }, [delay]);\n\n  // Clear timeout manually\n  const clear = useCallback(() => {\n    if (timeoutRef.current) {\n      clearTimeout(timeoutRef.current);\n      timeoutRef.current = null;\n    }\n  }, []);\n\n  return clear;\n}\n\n// Usage example\n// const clearTimeout = useTimeout(() => {\n//   setShowMessage(false);\n// }, 3000);\n// // Clear early if needed\n// \u003Cbutton onClick={clearTimeout}>Dismiss Now\u003C/button>",{"id":900,"category":847,"title":901,"description":902,"author":9,"date":10,"tags":903,"code":904,"canPreview":488},"react-use-localstorage-with-expiry","useLocalStorageWithExpiry Hook","A custom React Hook for persisting state to localStorage with expiration time and TypeScript support",[851,852,627,518],"import { useState, useEffect } from 'react';\n\ntype StoredValue\u003CT> = {\n  value: T;\n  expiry: number | null;\n};\n\nfunction useLocalStorageWithExpiry\u003CT>(\n  key: string,\n  initialValue: T,\n  expiryInMinutes = 60\n): [T, (value: T | ((val: T) => T)) => void, () => void] {\n  // Get initial value (check expiry)\n  const [storedValue, setStoredValue] = useState\u003CT>(() => {\n    if (typeof window === 'undefined') return initialValue;\n\n    try {\n      const item = window.localStorage.getItem(key);\n      if (!item) return initialValue;\n\n      const parsed = JSON.parse(item) as StoredValue\u003CT>;\n      // Check if expired\n      if (parsed.expiry && Date.now() > parsed.expiry) {\n        window.localStorage.removeItem(key);\n        return initialValue;\n      }\n      return parsed.value;\n    } catch (error) {\n      console.warn(`Error reading localStorage key \"${key}\":`, error);\n      return initialValue;\n    }\n  });\n\n  // Update localStorage with expiry\n  const setValue = (value: T | ((val: T) => T)) => {\n    try {\n      const valueToStore = value instanceof Function ? value(storedValue) : value;\n      setStoredValue(valueToStore);\n      if (typeof window !== 'undefined') {\n        const expiry = expiryInMinutes ? Date.now() + expiryInMinutes * 60 * 1000 : null;\n        window.localStorage.setItem(key, JSON.stringify({ value: valueToStore, expiry }));\n      }\n    } catch (error) {\n      console.warn(`Error setting localStorage key \"${key}\":`, error);\n    }\n  };\n\n  // Clear stored value\n  const clearValue = () => {\n    if (typeof window !== 'undefined') {\n      window.localStorage.removeItem(key);\n      setStoredValue(initialValue);\n    }\n  };\n\n  return [storedValue, setValue, clearValue];\n}\n\n// Usage example\n// const [token, setToken, clearToken] = useLocalStorageWithExpiry('auth-token', '', 15);\n// const [preferences, setPreferences] = useLocalStorageWithExpiry('user-prefs', { theme: 'light' }, 1440);",{"id":906,"category":847,"title":907,"description":908,"author":9,"date":10,"tags":909,"code":912,"canPreview":488},"react-use-reducer-with-localstorage","useReducerWithLocalStorage Hook","A custom React Hook combining useReducer with localStorage persistence (TypeScript support)",[851,852,910,627,911],"useReducer","StateManagement","import { useReducer, useEffect, Reducer } from 'react';\n\ntype ReducerAction\u003CT> = {\n  type: string;\n  payload?: T;\n};\n\nfunction useReducerWithLocalStorage\u003CS, A extends ReducerAction\u003Cunknown>>(\n  reducer: Reducer\u003CS, A>,\n  initialState: S,\n  key: string\n): [S, (action: A) => void] {\n  // Initialize state from localStorage or initialState\n  const getInitialState = (): S => {\n    if (typeof window === 'undefined') return initialState;\n    try {\n      const item = window.localStorage.getItem(key);\n      return item ? JSON.parse(item) : initialState;\n    } catch (error) {\n      console.warn(`Error reading localStorage key \"${key}\":`, error);\n      return initialState;\n    }\n  };\n\n  const [state, dispatch] = useReducer(reducer, initialState, getInitialState);\n\n  // Persist state to localStorage on change\n  useEffect(() => {\n    if (typeof window !== 'undefined') {\n      try {\n        window.localStorage.setItem(key, JSON.stringify(state));\n      } catch (error) {\n        console.warn(`Error setting localStorage key \"${key}\":`, error);\n      }\n    }\n  }, [state, key]);\n\n  return [state, dispatch];\n}\n\n// Usage example\n// type CounterState = { count: number };\n// type CounterAction = { type: 'INCREMENT' | 'DECREMENT' | 'RESET' };\n// const counterReducer = (state: CounterState, action: CounterAction): CounterState => {\n//   switch (action.type) {\n//     case 'INCREMENT': return { count: state.count + 1 };\n//     case 'DECREMENT': return { count: state.count - 1 };\n//     case 'RESET': return { count: 0 };\n//     default: return state;\n//   }\n// };\n// const [state, dispatch] = useReducerWithLocalStorage(counterReducer, { count: 0 }, 'counter-state');",{"id":914,"category":847,"title":915,"description":916,"author":9,"date":10,"tags":917,"code":919,"canPreview":488},"react-use-localstorage","useLocalStorage Hook","A minimal custom React Hook for persisting state to localStorage with TypeScript support (without expiry)",[851,852,627,890,918],"Persistence","import { useState, useEffect } from 'react';\n\nfunction useLocalStorage\u003CT>(key: string, initialValue: T): [T, (value: T | ((val: T) => T)) => void] {\n  const [storedValue, setStoredValue] = useState\u003CT>(() => {\n    if (typeof window === 'undefined') return initialValue;\n    try {\n      const item = window.localStorage.getItem(key);\n      return item ? JSON.parse(item) : initialValue;\n    } catch (error) {\n      console.warn(`Error reading localStorage key \"${key}\":`, error);\n      return initialValue;\n    }\n  });\n\n  const setValue = (value: T | ((val: T) => T)) => {\n    try {\n      const valueToStore = value instanceof Function ? value(storedValue) : value;\n      setStoredValue(valueToStore);\n      if (typeof window !== 'undefined') {\n        window.localStorage.setItem(key, JSON.stringify(valueToStore));\n      }\n    } catch (error) {\n      console.warn(`Error setting localStorage key \"${key}\":`, error);\n    }\n  };\n\n  return [storedValue, setValue];\n}\n\n// Usage example\n// const [theme, setTheme] = useLocalStorage('app-theme', 'light');\n// const [userSettings, setUserSettings] = useLocalStorage('user-settings', { notifications: true });",{"id":921,"category":847,"title":922,"description":923,"author":9,"date":10,"tags":924,"code":925,"canPreview":488},"react-use-sessionstorage","useSessionStorage Hook","A custom React Hook for persisting state to sessionStorage with TypeScript support",[851,852,628,890,918],"import { useState, useEffect } from 'react';\n\nfunction useSessionStorage\u003CT>(key: string, initialValue: T): [T, (value: T | ((val: T) => T)) => void] {\n  const [storedValue, setStoredValue] = useState\u003CT>(() => {\n    if (typeof window === 'undefined') return initialValue;\n    try {\n      const item = window.sessionStorage.getItem(key);\n      return item ? JSON.parse(item) : initialValue;\n    } catch (error) {\n      console.warn(`Error reading sessionStorage key \"${key}\":`, error);\n      return initialValue;\n    }\n  });\n\n  const setValue = (value: T | ((val: T) => T)) => {\n    try {\n      const valueToStore = value instanceof Function ? value(storedValue) : value;\n      setStoredValue(valueToStore);\n      if (typeof window !== 'undefined') {\n        window.sessionStorage.setItem(key, JSON.stringify(valueToStore));\n      }\n    } catch (error) {\n      console.warn(`Error setting sessionStorage key \"${key}\":`, error);\n    }\n  };\n\n  return [storedValue, setValue];\n}\n\n// Usage example\n// const [tempFormData, setTempFormData] = useSessionStorage('checkout-form', { step: 1, items: [] });\n// const [sessionToken, setSessionToken] = useSessionStorage('session-token', '');",{"id":927,"category":847,"title":928,"description":929,"author":9,"date":10,"tags":930,"code":931,"canPreview":488},"react-use-keypress","useKeyPress Hook","A custom React Hook to detect keyboard key presses with TypeScript support",[851,852,820,699,15],"import { useState, useEffect } from 'react';\n\nfunction useKeyPress(targetKey: string | string[]): boolean {\n  const [keyPressed, setKeyPressed] = useState(false);\n  const targetKeys = Array.isArray(targetKey) ? targetKey : [targetKey];\n\n  const downHandler = ({ key }: KeyboardEvent) => {\n    if (targetKeys.includes(key)) setKeyPressed(true);\n  };\n\n  const upHandler = ({ key }: KeyboardEvent) => {\n    if (targetKeys.includes(key)) setKeyPressed(false);\n  };\n\n  useEffect(() => {\n    window.addEventListener('keydown', downHandler);\n    window.addEventListener('keyup', upHandler);\n    window.addEventListener('blur', () => setKeyPressed(false));\n\n    return () => {\n      window.removeEventListener('keydown', downHandler);\n      window.removeEventListener('keyup', upHandler);\n      window.removeEventListener('blur', () => setKeyPressed(false));\n    };\n  }, [targetKeys]);\n\n  return keyPressed;\n}\n\n// Usage example\n// const isEscapePressed = useKeyPress('Escape');\n// const isCtrlSPressed = useKeyPress(['Control', 's']);\n// useEffect(() => {\n//   if (isEscapePressed) setIsModalOpen(false);\n// }, [isEscapePressed]);",{"id":933,"category":847,"title":934,"description":935,"author":9,"date":10,"tags":936,"code":938,"canPreview":488},"react-use-longpress","useLongPress Hook","A custom React Hook to detect long press events on elements with TypeScript support",[851,852,937,699,15],"Touch","import { useCallback, useRef, useState } from 'react';\n\ntype LongPressOptions = {\n  delay?: number;\n  onLongPress: (e: React.MouseEvent | React.TouchEvent) => void;\n  onClick?: (e: React.MouseEvent | React.TouchEvent) => void;\n};\n\nfunction useLongPress({ delay = 500, onLongPress, onClick }: LongPressOptions) {\n  const [isPressing, setIsPressing] = useState(false);\n  const timerRef = useRef\u003CNodeJS.Timeout | null>(null);\n  const eventRef = useRef\u003CReact.MouseEvent | React.TouchEvent | null>(null);\n\n  const startPress = useCallback((e: React.MouseEvent | React.TouchEvent) => {\n    e.preventDefault();\n    eventRef.current = e;\n    setIsPressing(true);\n    timerRef.current = setTimeout(() => {\n      onLongPress(e);\n      setIsPressing(false);\n    }, delay);\n  }, [delay, onLongPress]);\n\n  const endPress = useCallback((e: React.MouseEvent | React.TouchEvent) => {\n    e.preventDefault();\n    if (timerRef.current) clearTimeout(timerRef.current);\n    if (isPressing && onClick && eventRef.current) {\n      onClick(eventRef.current);\n    }\n    setIsPressing(false);\n    eventRef.current = null;\n  }, [isPressing, onClick]);\n\n  const cancelPress = useCallback(() => {\n    if (timerRef.current) clearTimeout(timerRef.current);\n    setIsPressing(false);\n    eventRef.current = null;\n  }, []);\n\n  return {\n    onMouseDown: startPress,\n    onMouseUp: endPress,\n    onMouseLeave: cancelPress,\n    onTouchStart: startPress,\n    onTouchEnd: endPress,\n    onTouchCancel: cancelPress,\n  };\n}\n\n// Usage example\n// const longPressHandlers = useLongPress({\n//   onLongPress: () => console.log('Long press!'),\n//   onClick: () => console.log('Click!'),\n//   delay: 600\n// });\n// \u003Cbutton {...longPressHandlers}>Long Press Me\u003C/button>",{"id":940,"category":847,"title":941,"description":942,"author":9,"date":10,"tags":943,"code":946,"canPreview":488},"react-use-window-size","useWindowSize Hook","A custom React Hook to track window size changes with TypeScript support",[851,852,944,644,945],"Window","Layout","import { useState, useEffect } from 'react';\n\ntype WindowSize = {\n  width: number;\n  height: number;\n};\n\nfunction useWindowSize(): WindowSize {\n  const [windowSize, setWindowSize] = useState\u003CWindowSize>({\n    width: typeof window !== 'undefined' ? window.innerWidth : 0,\n    height: typeof window !== 'undefined' ? window.innerHeight : 0,\n  });\n\n  useEffect(() => {\n    if (typeof window === 'undefined') return;\n\n    const handleResize = () => {\n      setWindowSize({\n        width: window.innerWidth,\n        height: window.innerHeight,\n      });\n    };\n\n    window.addEventListener('resize', handleResize);\n    window.addEventListener('orientationchange', handleResize);\n\n    return () => {\n      window.removeEventListener('resize', handleResize);\n      window.removeEventListener('orientationchange', handleResize);\n    };\n  }, []);\n\n  return windowSize;\n}\n\n// Usage example\n// const { width, height } = useWindowSize();\n// const isDesktop = width >= 1024;\n// const isPortrait = height > width;",{"id":948,"category":847,"title":949,"description":950,"author":9,"date":10,"tags":951,"code":952,"canPreview":488},"react-use-scroll-position","useScrollPosition Hook","A custom React Hook to track scroll position of window/element with TypeScript support",[851,852,111,699,15],"import { useState, useEffect, RefObject } from 'react';\n\ntype ScrollPosition = {\n  x: number;\n  y: number;\n};\n\nfunction useScrollPosition\u003CT extends HTMLElement = HTMLElement>(\n  elementRef?: RefObject\u003CT>\n): ScrollPosition {\n  const [scrollPosition, setScrollPosition] = useState\u003CScrollPosition>({\n    x: 0,\n    y: 0,\n  });\n\n  useEffect(() => {\n    const target = elementRef?.current || window;\n    if (!target) return;\n\n    const handleScroll = () => {\n      setScrollPosition({\n        x: target === window ? window.scrollX : target.scrollLeft,\n        y: target === window ? window.scrollY : target.scrollTop,\n      });\n    };\n\n    target.addEventListener('scroll', handleScroll, { passive: true });\n    handleScroll(); // Initial position\n\n    return () => {\n      target.removeEventListener('scroll', handleScroll);\n    };\n  }, [elementRef]);\n\n  return scrollPosition;\n}\n\n// Usage example\n// // Track window scroll\n// const { y: scrollY } = useScrollPosition();\n// const isScrolled = scrollY > 100;\n\n// // Track element scroll\n// const containerRef = useRef\u003CHTMLDivElement>(null);\n// const { y: containerScrollY } = useScrollPosition(containerRef);",{"id":954,"category":847,"title":955,"description":956,"author":9,"date":10,"tags":957,"code":958,"canPreview":488},"react-use-toggle","useToggle Hook","A minimal custom React Hook for boolean state toggling with TypeScript support",[851,852,890,563],"import { useState, useCallback } from 'react';\n\nfunction useToggle(initialValue = false): [boolean, () => void, (value: boolean) => void] {\n  const [value, setValue] = useState(initialValue);\n\n  const toggle = useCallback(() => {\n    setValue(prev => !prev);\n  }, []);\n\n  const setToggle = useCallback((newValue: boolean) => {\n    setValue(newValue);\n  }, []);\n\n  return [value, toggle, setToggle];\n}\n\n// Usage example\n// const [isModalOpen, toggleModal, setModalOpen] = useToggle(false);\n// \u003Cbutton onClick={toggleModal}>Toggle Modal\u003C/button>\n// \u003Cbutton onClick={() => setModalOpen(true)}>Open Modal\u003C/button>",{"id":960,"category":847,"title":961,"description":962,"author":9,"date":10,"tags":963,"code":964,"canPreview":488},"react-use-array","useArray Hook","A custom React Hook for array state management with common operations (TypeScript)",[851,852,890,791,563],"import { useState, useCallback } from 'react';\n\nfunction useArray\u003CT>(initialValue: T[] = []): {\n  array: T[];\n  setArray: React.Dispatch\u003CReact.SetStateAction\u003CT[]>>;\n  push: (item: T) => void;\n  pop: () => void;\n  shift: () => void;\n  unshift: (item: T) => void;\n  splice: (index: number, deleteCount: number, ...items: T[]) => void;\n  filter: (callback: (item: T, index: number, array: T[]) => boolean) => void;\n  map: (callback: (item: T, index: number, array: T[]) => T) => void;\n  clear: () => void;\n  removeById: (idKey: keyof T, id: T[keyof T]) => void;\n} {\n  const [array, setArray] = useState\u003CT[]>(initialValue);\n\n  const push = useCallback((item: T) => {\n    setArray(prev => [...prev, item]);\n  }, []);\n\n  const pop = useCallback(() => {\n    setArray(prev => prev.slice(0, -1));\n  }, []);\n\n  const shift = useCallback(() => {\n    setArray(prev => prev.slice(1));\n  }, []);\n\n  const unshift = useCallback((item: T) => {\n    setArray(prev => [item, ...prev]);\n  }, []);\n\n  const splice = useCallback((index: number, deleteCount: number, ...items: T[]) => {\n    setArray(prev => {\n      const newArray = [...prev];\n      newArray.splice(index, deleteCount, ...items);\n      return newArray;\n    });\n  }, []);\n\n  const filter = useCallback((callback: (item: T, index: number, array: T[]) => boolean) => {\n    setArray(prev => prev.filter(callback));\n  }, []);\n\n  const map = useCallback((callback: (item: T, index: number, array: T[]) => T) => {\n    setArray(prev => prev.map(callback));\n  }, []);\n\n  const clear = useCallback(() => {\n    setArray([]);\n  }, []);\n\n  const removeById = useCallback((idKey: keyof T, id: T[keyof T]) => {\n    setArray(prev => prev.filter(item => item[idKey] !== id));\n  }, []);\n\n  return {\n    array,\n    setArray,\n    push,\n    pop,\n    shift,\n    unshift,\n    splice,\n    filter,\n    map,\n    clear,\n    removeById,\n  };\n}\n\n// Usage example\n// const { array: todos, push, removeById, clear } = useArray([\n//   { id: 1, text: 'Learn React' },\n//   { id: 2, text: 'Build Hooks' }\n// ]);\n// push({ id: 3, text: 'Use useArray' });\n// removeById('id', 2);\n// clear();",{"id":966,"category":847,"title":967,"description":968,"author":9,"date":10,"tags":969,"code":971,"canPreview":488},"react-use-debounced-callback","useDebouncedCallback Hook","A custom React Hook for debouncing functions/callbacks with TypeScript support",[851,852,620,486,970],"Callbacks","import { useCallback, useRef } from 'react';\n\nfunction useDebouncedCallback\u003CT extends (...args: any[]) => any>(\n  callback: T,\n  delay = 500,\n  leading = false\n): T {\n  const timeoutRef = useRef\u003CNodeJS.Timeout | null>(null);\n  const callbackRef = useRef(callback);\n\n  // Update callback ref on each render\n  callbackRef.current = callback;\n\n  const debouncedCallback = useCallback((...args: Parameters\u003CT>) => {\n    const execute = () => {\n      callbackRef.current(...args);\n    };\n\n    if (timeoutRef.current) clearTimeout(timeoutRef.current);\n\n    if (leading && !timeoutRef.current) {\n      execute();\n    }\n\n    timeoutRef.current = setTimeout(() => {\n      if (!leading) execute();\n      timeoutRef.current = null;\n    }, delay);\n  }, [delay, leading]) as T;\n\n  // Clear timeout on unmount\n  const cancel = useCallback(() => {\n    if (timeoutRef.current) {\n      clearTimeout(timeoutRef.current);\n      timeoutRef.current = null;\n    }\n  }, []);\n\n  // Attach cancel method to the debounced callback\n  (debouncedCallback as any).cancel = cancel;\n\n  return debouncedCallback;\n}\n\n// Usage example\n// const handleSearch = useDebouncedCallback((query) => {\n//   fetch(`/api/search?q=${query}`);\n// }, 300);\n\n// \u003Cinput onChange={(e) => handleSearch(e.target.value)} />\n// // Cancel debounce if needed\n// \u003Cbutton onClick={() => handleSearch.cancel()}>Cancel Search\u003C/button>",{"id":973,"category":847,"title":974,"description":975,"author":9,"date":10,"tags":976,"code":978,"canPreview":488},"react-use-throttled-callback","useThrottledCallback Hook","A custom React Hook for throttling functions/callbacks with TypeScript support",[851,852,977,486,970],"Throttle","import { useCallback, useRef } from 'react';\n\nfunction useThrottledCallback\u003CT extends (...args: any[]) => any>(\n  callback: T,\n  delay = 500,\n  leading = true,\n  trailing = true\n): T {\n  const timeoutRef = useRef\u003CNodeJS.Timeout | null>(null);\n  const lastExecRef = useRef\u003Cnumber>(0);\n  const callbackRef = useRef(callback);\n  const argsRef = useRef\u003CParameters\u003CT>>([]);\n\n  // Update callback ref on each render\n  callbackRef.current = callback;\n\n  const throttledCallback = useCallback((...args: Parameters\u003CT>) => {\n    argsRef.current = args;\n    const now = Date.now();\n    const elapsed = now - lastExecRef.current;\n\n    const execute = () => {\n      lastExecRef.current = now;\n      callbackRef.current(...argsRef.current);\n    };\n\n    // Leading execution\n    if (leading && elapsed >= delay) {\n      execute();\n    }\n    // Trailing execution\n    else if (trailing && !timeoutRef.current) {\n      timeoutRef.current = setTimeout(() => {\n        execute();\n        timeoutRef.current = null;\n      }, delay - elapsed);\n    }\n  }, [delay, leading, trailing]) as T;\n\n  // Cancel throttle\n  const cancel = useCallback(() => {\n    if (timeoutRef.current) {\n      clearTimeout(timeoutRef.current);\n      timeoutRef.current = null;\n    }\n  }, []);\n\n  // Attach cancel method\n  (throttledCallback as any).cancel = cancel;\n\n  return throttledCallback;\n}\n\n// Usage example\n// const handleScroll = useThrottledCallback(() => {\n//   console.log('Scroll position:', window.scrollY);\n// }, 200);\n\n// useEffect(() => {\n//   window.addEventListener('scroll', handleScroll, { passive: true });\n//   return () => window.removeEventListener('scroll', handleScroll);\n// }, [handleScroll]);",{"id":980,"category":847,"title":981,"description":982,"author":9,"date":10,"tags":983,"code":985,"canPreview":488},"react-use-async","useAsync Hook","A custom React Hook for handling async operations with loading/error states (TypeScript)",[851,852,549,984,865],"Promises","import { useState, useCallback, useRef, useEffect } from 'react';\n\ntype AsyncState\u003CT> = {\n  data: T | null;\n  loading: boolean;\n  error: Error | null;\n};\n\ntype AsyncOptions = {\n  autoExecute?: boolean;\n  onSuccess?: (data: any) => void;\n  onError?: (error: Error) => void;\n};\n\nfunction useAsync\u003CT>(\n  asyncFunction: (...args: any[]) => Promise\u003CT>,\n  options: AsyncOptions = {}\n): {\n  state: AsyncState\u003CT>;\n  execute: (...args: any[]) => Promise\u003CT | null>;\n  reset: () => void;\n} {\n  const { autoExecute = true, onSuccess, onError } = options;\n  const [state, setState] = useState\u003CAsyncState\u003CT>>({\n    data: null,\n    loading: false,\n    error: null,\n  });\n  const isMountedRef = useRef(true);\n\n  // Cleanup on unmount\n  useEffect(() => {\n    return () => {\n      isMountedRef.current = false;\n    };\n  }, []);\n\n  const execute = useCallback(async (...args: any[]) => {\n    if (!isMountedRef.current) return null;\n    setState(prev => ({ ...prev, loading: true, error: null }));\n    try {\n      const data = await asyncFunction(...args);\n      if (!isMountedRef.current) return null;\n      setState({ data, loading: false, error: null });\n      onSuccess?.(data);\n      return data;\n    } catch (error) {\n      if (!isMountedRef.current) return null;\n      const err = error as Error;\n      setState({ data: null, loading: false, error: err });\n      onError?.(err);\n      return null;\n    }\n  }, [asyncFunction, onSuccess, onError]);\n\n  const reset = useCallback(() => {\n    setState({ data: null, loading: false, error: null });\n  }, []);\n\n  // Auto execute on mount\n  useEffect(() => {\n    if (autoExecute) {\n      execute();\n    }\n  }, [execute, autoExecute]);\n\n  return { state, execute, reset };\n}\n\n// Usage example\n// const fetchUser = (id: number) => fetch(`/api/users/${id}`).then(res => res.json());\n// const { state: { data: user, loading, error }, execute: fetchUserById } = useAsync(fetchUser, { autoExecute: false });\n// \u003Cbutton onClick={() => fetchUserById(1)}>Load User\u003C/button>",{"id":987,"category":847,"title":988,"description":989,"author":9,"date":10,"tags":990,"code":992,"canPreview":488},"react-use-idle","useIdle Hook","A custom React Hook to detect user idle/inactivity with TypeScript support",[851,852,991,699,15],"UserActivity","import { useState, useEffect, useRef } from 'react';\n\nfunction useIdle(\n  timeout = 30000, // 30 seconds default\n  events: string[] = ['mousemove', 'keydown', 'mousedown', 'touchstart', 'scroll']\n): boolean {\n  const [isIdle, setIsIdle] = useState(false);\n  const timerRef = useRef\u003CNodeJS.Timeout | null>(null);\n\n  const resetTimer = () => {\n    if (timerRef.current) clearTimeout(timerRef.current);\n    setIsIdle(false);\n    timerRef.current = setTimeout(() => {\n      setIsIdle(true);\n    }, timeout);\n  };\n\n  useEffect(() => {\n    // Initial timer\n    resetTimer();\n\n    // Add event listeners\n    events.forEach(event => {\n      window.addEventListener(event, resetTimer, { passive: true });\n    });\n\n    return () => {\n      // Cleanup\n      if (timerRef.current) clearTimeout(timerRef.current);\n      events.forEach(event => {\n        window.removeEventListener(event, resetTimer);\n      });\n    };\n  }, [timeout, events]);\n\n  return isIdle;\n}\n\n// Usage example\n// const isUserIdle = useIdle(60000); // 1 minute\n// useEffect(() => {\n//   if (isUserIdle) {\n//     console.log('User is idle!');\n//     // Show timeout modal, pause video, etc.\n//   }\n// }, [isUserIdle]);",{"id":994,"category":847,"title":995,"description":996,"author":9,"date":10,"tags":997,"code":999,"canPreview":488},"react-use-focus","useFocus Hook","A custom React Hook to manage focus state of an element with TypeScript support",[851,852,998,698,767],"Focus","import { useState, useEffect, RefObject, useCallback } from 'react';\n\nfunction useFocus\u003CT extends HTMLElement = HTMLElement>(\n  ref: RefObject\u003CT>\n): [boolean, () => void, () => void] {\n  const [isFocused, setIsFocused] = useState(false);\n\n  const handleFocus = useCallback(() => setIsFocused(true), []);\n  const handleBlur = useCallback(() => setIsFocused(false), []);\n\n  useEffect(() => {\n    const element = ref.current;\n    if (!element) return;\n\n    element.addEventListener('focus', handleFocus);\n    element.addEventListener('blur', handleBlur);\n\n    return () => {\n      element.removeEventListener('focus', handleFocus);\n      element.removeEventListener('blur', handleBlur);\n    };\n  }, [ref, handleFocus, handleBlur]);\n\n  const focus = useCallback(() => {\n    ref.current?.focus();\n  }, [ref]);\n\n  const blur = useCallback(() => {\n    ref.current?.blur();\n  }, [ref]);\n\n  return [isFocused, focus, blur];\n}\n\n// Usage example\n// const inputRef = useRef\u003CHTMLInputElement>(null);\n// const [isInputFocused, focusInput, blurInput] = useFocus(inputRef);\n// \u003Cinput ref={inputRef} />\n// \u003Cbutton onClick={focusInput}>Focus Input\u003C/button>\n// \u003Cbutton onClick={blurInput}>Blur Input\u003C/button>\n// {isInputFocused && \u003Cp>Input is focused!\u003C/p>}",{"id":1001,"category":847,"title":1002,"description":1003,"author":9,"date":10,"tags":1004,"code":1005,"canPreview":488},"react-use-hover","useHover Hook","A custom React Hook to detect hover state of an element with TypeScript support",[851,852,28,698,15],"import { useState, useEffect, RefObject, useCallback } from 'react';\n\nfunction useHover\u003CT extends HTMLElement = HTMLElement>(\n  ref: RefObject\u003CT>\n): boolean {\n  const [isHovering, setIsHovering] = useState(false);\n\n  const handleMouseEnter = useCallback(() => setIsHovering(true), []);\n  const handleMouseLeave = useCallback(() => setIsHovering(false), []);\n\n  useEffect(() => {\n    const element = ref.current;\n    if (!element) return;\n\n    element.addEventListener('mouseenter', handleMouseEnter);\n    element.addEventListener('mouseleave', handleMouseLeave);\n\n    return () => {\n      element.removeEventListener('mouseenter', handleMouseEnter);\n      element.removeEventListener('mouseleave', handleMouseLeave);\n    };\n  }, [ref, handleMouseEnter, handleMouseLeave]);\n\n  return isHovering;\n}\n\n// Usage example\n// const buttonRef = useRef\u003CHTMLButtonElement>(null);\n// const isButtonHovered = useHover(buttonRef);\n// \u003Cbutton ref={buttonRef} style={{ backgroundColor: isButtonHovered ? 'blue' : 'gray' }}>\n//   Hover Me\n// \u003C/button>",{"id":1007,"category":847,"title":1008,"description":1009,"author":9,"date":10,"tags":1010,"code":1012,"canPreview":488},"react-use-document-title","useDocumentTitle Hook","A custom React Hook to manage document title with TypeScript support",[851,852,1011,15,563],"Document","import { useEffect, useRef } from 'react';\n\nfunction useDocumentTitle(title: string, restoreOnUnmount = true): void {\n  const originalTitle = useRef\u003Cstring | null>(null);\n\n  useEffect(() => {\n    // Save original title on first mount\n    if (originalTitle.current === null) {\n      originalTitle.current = document.title;\n    }\n\n    // Update title\n    document.title = title;\n\n    // Restore original title on unmount if needed\n    return () => {\n      if (restoreOnUnmount && originalTitle.current) {\n        document.title = originalTitle.current;\n      }\n    };\n  }, [title, restoreOnUnmount]);\n}\n\n// Usage example\n// useDocumentTitle('Home | My App');\n\n// // Restore original title when component unmounts\n// useDocumentTitle('Profile | My App', true);\n\n// // Keep new title after unmount\n// useDocumentTitle('Error 404 | My App', false);",{"id":1014,"category":847,"title":1015,"description":1016,"author":9,"date":10,"tags":1017,"code":1021,"canPreview":488},"react-use-script","useScript Hook","A custom React Hook to dynamically load external scripts with TypeScript support",[851,852,1018,1019,1020],"Scripts","DynamicLoading","External","import { useState, useEffect } from 'react';\n\ntype ScriptStatus = 'idle' | 'loading' | 'ready' | 'error';\n\nfunction useScript(src: string): ScriptStatus {\n  const [status, setStatus] = useState\u003CScriptStatus>(() => {\n    if (typeof window === 'undefined') return 'idle';\n    // Check if script already exists\n    const existingScript = document.querySelector(`script[src=\"${src}\"]`);\n    return existingScript ? 'ready' : 'idle';\n  });\n\n  useEffect(() => {\n    if (typeof window === 'undefined' || status === 'ready') return;\n\n    let script: HTMLScriptElement | null = document.querySelector(`script[src=\"${src}\"]`);\n\n    if (!script) {\n      script = document.createElement('script');\n      script.src = src;\n      script.async = true;\n      script.setAttribute('data-status', 'loading');\n      document.body.appendChild(script);\n\n      // Update status attributes\n      const setAttributeFromEvent = (event: Event) => {\n        if (!script) return;\n        const newStatus = event.type === 'load' ? 'ready' : 'error';\n        script.setAttribute('data-status', newStatus);\n        setStatus(newStatus);\n      };\n\n      script.addEventListener('load', setAttributeFromEvent);\n      script.addEventListener('error', setAttributeFromEvent);\n    } else {\n      // Use existing script status\n      setStatus(script.getAttribute('data-status') as ScriptStatus || 'ready');\n    }\n\n    // Cleanup\n    return () => {\n      if (script) {\n        script.removeEventListener('load', setAttributeFromEvent);\n        script.removeEventListener('error', setAttributeFromEvent);\n      }\n    };\n\n    function setAttributeFromEvent(event: Event) {\n      if (!script) return;\n      const newStatus = event.type === 'load' ? 'ready' : 'error';\n      script.setAttribute('data-status', newStatus);\n      setStatus(newStatus);\n    }\n  }, [src, status]);\n\n  return status;\n}\n\n// Usage example\n// const scriptStatus = useScript('https://cdn.jsdelivr.net/npm/chart.js');\n// if (scriptStatus === 'ready') {\n//   // Initialize Chart.js\n// } else if (scriptStatus === 'error') {\n//   console.error('Failed to load Chart.js');\n// }",{"id":1023,"category":847,"title":1024,"description":1025,"author":9,"date":10,"tags":1026,"code":1027,"canPreview":488},"react-use-resize-observer","useResizeObserver Hook","A custom React Hook to track element size changes with ResizeObserver API (TypeScript)",[851,852,689,945,486],"import { useState, useEffect, RefObject } from 'react';\n\ntype ElementSize = {\n  width: number;\n  height: number;\n  top: number;\n  left: number;\n};\n\nfunction useResizeObserver\u003CT extends HTMLElement = HTMLElement>(\n  ref: RefObject\u003CT>\n): ElementSize | null {\n  const [size, setSize] = useState\u003CElementSize | null>(null);\n\n  useEffect(() => {\n    const element = ref.current;\n    if (!element || !window.ResizeObserver) return;\n\n    const resizeObserver = new ResizeObserver((entries) => {\n      const entry = entries[0];\n      if (entry) {\n        const { width, height, top, left } = entry.contentRect;\n        setSize({ width, height, top, left });\n      }\n    });\n\n    resizeObserver.observe(element);\n\n    return () => {\n      resizeObserver.unobserve(element);\n      resizeObserver.disconnect();\n    };\n  }, [ref]);\n\n  return size;\n}\n\n// Usage example\n// const containerRef = useRef\u003CHTMLDivElement>(null);\n// const size = useResizeObserver(containerRef);\n// \u003Cdiv ref={containerRef}>\n//   {size && \u003Cp>Width: {size.width}px, Height: {size.height}px\u003C/p>}\n// \u003C/div>",{"id":1029,"category":847,"title":1030,"description":1031,"author":9,"date":10,"tags":1032,"code":1034,"canPreview":488},"react-use-online-status","useOnlineStatus Hook","A custom React Hook to detect network online/offline status with TypeScript support",[851,852,782,1033,15],"Connectivity","import { useState, useEffect } from 'react';\n\nfunction useOnlineStatus(): boolean {\n  const [isOnline, setIsOnline] = useState(() => {\n    if (typeof window === 'undefined') return true;\n    return window.navigator.onLine;\n  });\n\n  useEffect(() => {\n    if (typeof window === 'undefined') return;\n\n    const handleOnline = () => setIsOnline(true);\n    const handleOffline = () => setIsOnline(false);\n\n    window.addEventListener('online', handleOnline);\n    window.addEventListener('offline', handleOffline);\n\n    return () => {\n      window.removeEventListener('online', handleOnline);\n      window.removeEventListener('offline', handleOffline);\n    };\n  }, []);\n\n  return isOnline;\n}\n\n// Usage example\n// const isOnline = useOnlineStatus();\n// \u003Cdiv className={isOnline ? 'online' : 'offline'}>\n//   {isOnline ? 'Connected' : 'No internet connection'}\n// \u003C/div>\n// useEffect(() => {\n//   if (!isOnline) {\n//     // Show offline notification\n//   }\n// }, [isOnline]);",{"id":1036,"category":847,"title":1037,"description":1038,"author":9,"date":10,"tags":1039,"code":1040,"canPreview":488},"react-use-clipboard","useClipboard Hook","A custom React Hook for clipboard copy/paste functionality with TypeScript support",[851,852,675,15,563],"import { useState, useCallback } from 'react';\n\ntype ClipboardResult = {\n  copied: boolean;\n  copy: (text: string, options?: ClipboardCopyOptions) => Promise\u003Cvoid>;\n  clear: () => void;\n};\n\ntype ClipboardCopyOptions = {\n  onSuccess?: () => void;\n  onError?: (error: Error) => void;\n  timeout?: number;\n};\n\nfunction useClipboard(defaultTimeout = 2000): ClipboardResult {\n  const [copied, setCopied] = useState(false);\n\n  const copy = useCallback(async (\n    text: string,\n    options: ClipboardCopyOptions = {}\n  ) => {\n    const { onSuccess, onError, timeout = defaultTimeout } = options;\n    try {\n      await navigator.clipboard.writeText(text);\n      setCopied(true);\n      onSuccess?.();\n      \n      // Reset copied state after timeout\n      setTimeout(() => setCopied(false), timeout);\n    } catch (error) {\n      setCopied(false);\n      onError?.(error as Error);\n      console.error('Failed to copy to clipboard:', error);\n    }\n  }, [defaultTimeout]);\n\n  const clear = useCallback(() => {\n    setCopied(false);\n  }, []);\n\n  return { copied, copy, clear };\n}\n\n// Usage example\n// const { copied, copy } = useClipboard();\n// \u003Cbutton onClick={() => copy('Hello World!', {\n//   onSuccess: () => console.log('Copied!'),\n//   onError: (err) => console.error('Copy failed:', err)\n// })}>\n//   {copied ? 'Copied!' : 'Copy Text'}\n// \u003C/button>",{"id":1042,"category":847,"title":1043,"description":1044,"author":9,"date":10,"tags":1045,"code":1046,"canPreview":488},"react-use-countdown","useCountdown Hook","A custom React Hook for countdown timer with TypeScript support",[851,852,660,659,15],"import { useState, useEffect, useRef, useCallback } from 'react';\n\ntype CountdownState = {\n  seconds: number;\n  minutes: number;\n  hours: number;\n  days: number;\n  isRunning: boolean;\n  isFinished: boolean;\n};\n\nfunction useCountdown(\n  targetDate: Date | number,\n  autoStart = true\n): {\n  state: CountdownState;\n  start: () => void;\n  pause: () => void;\n  reset: () => void;\n} {\n  const [state, setState] = useState\u003CCountdownState>({\n    seconds: 0,\n    minutes: 0,\n    hours: 0,\n    days: 0,\n    isRunning: autoStart,\n    isFinished: false,\n  });\n  const intervalRef = useRef\u003CNodeJS.Timeout | null>(null);\n  const targetTimestamp = useRef\u003Cnumber>(\n    typeof targetDate === 'number' ? targetDate : targetDate.getTime()\n  );\n\n  // Calculate remaining time\n  const calculateRemainingTime = useCallback(() => {\n    const now = Date.now();\n    const diff = targetTimestamp.current - now;\n\n    if (diff \u003C= 0) {\n      return {\n        seconds: 0,\n        minutes: 0,\n        hours: 0,\n        days: 0,\n        isFinished: true,\n      };\n    }\n\n    const days = Math.floor(diff / (1000 * 60 * 60 * 24));\n    const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));\n    const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));\n    const seconds = Math.floor((diff % (1000 * 60)) / 1000);\n\n    return {\n      days,\n      hours,\n      minutes,\n      seconds,\n      isFinished: false,\n    };\n  }, []);\n\n  // Update countdown\n  const updateCountdown = useCallback(() => {\n    const remaining = calculateRemainingTime();\n    setState(prev => ({ ...prev, ...remaining }));\n\n    if (remaining.isFinished) {\n      pause();\n    }\n  }, [calculateRemainingTime]);\n\n  // Start countdown\n  const start = useCallback(() => {\n    if (state.isFinished || intervalRef.current) return;\n    setState(prev => ({ ...prev, isRunning: true }));\n    intervalRef.current = setInterval(updateCountdown, 1000);\n    updateCountdown(); // Immediate update\n  }, [state.isFinished, updateCountdown]);\n\n  // Pause countdown\n  const pause = useCallback(() => {\n    if (intervalRef.current) {\n      clearInterval(intervalRef.current);\n      intervalRef.current = null;\n      setState(prev => ({ ...prev, isRunning: false }));\n    }\n  }, []);\n\n  // Reset countdown\n  const reset = useCallback(() => {\n    pause();\n    const remaining = calculateRemainingTime();\n    setState({\n      ...remaining,\n      isRunning: autoStart,\n      isFinished: remaining.isFinished,\n    });\n    if (autoStart && !remaining.isFinished) {\n      start();\n    }\n  }, [pause, calculateRemainingTime, autoStart, start]);\n\n  // Initial setup\n  useEffect(() => {\n    if (autoStart) {\n      start();\n    } else {\n      updateCountdown();\n    }\n\n    // Cleanup\n    return () => {\n      pause();\n    };\n  }, [autoStart, start, updateCountdown, pause]);\n\n  return { state, start, pause, reset };\n}\n\n// Usage example\n// const targetDate = new Date();\n// targetDate.setDate(targetDate.getDate() + 1); // 1 day from now\n// const { state, start, pause, reset } = useCountdown(targetDate);\n// \u003Cdiv>\n//   \u003Cp>{state.days}d {state.hours}h {state.minutes}m {state.seconds}s\u003C/p>\n//   \u003Cbutton onClick={start} disabled={state.isRunning || state.isFinished}>Start\u003C/button>\n//   \u003Cbutton onClick={pause} disabled={!state.isRunning}>Pause\u003C/button>\n//   \u003Cbutton onClick={reset}>Reset\u003C/button>\n// \u003C/div>",[1048,1053,1057,1062],{"id":6,"name":1049,"description":1050,"icon":1051,"color":1052},"CSS","CSS style snippets with live preview support","palette","#264de4",{"id":480,"name":484,"description":1054,"icon":1055,"color":1056},"TypeScript utility snippets and helper functions","code","#3178c6",{"id":607,"name":1058,"description":1059,"icon":1060,"color":1061},"Vue","Vue 3 components and Composition API snippets","component","#42b883",{"id":847,"name":851,"description":1063,"icon":1064,"color":1065},"React Hooks and component snippets","atom","#61dafb",1765529598366]