From 46d9322b5072ec854f8403f6e560eff73f5b2fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Sun, 15 Feb 2026 14:43:52 +0100 Subject: [PATCH 01/11] stable with basic suggestion --- .../editor/metadataEditor/metadataEditor.less | 5 + client/homebrew/editor/tagInput/tagInput.jsx | 225 +++++++++++------- .../editor/tagInput/tagSuggestionList.js | 1 + 3 files changed, 149 insertions(+), 82 deletions(-) create mode 100644 client/homebrew/editor/tagInput/tagSuggestionList.js diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index fd04f07d9..df915a546 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -114,6 +114,11 @@ z-index : 200; max-width : 150px; } + + &.tags .tagInput-dropdown { + z-index : 201; + max-width : 150px; + } } diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 8ed006283..eb5912f23 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -1,100 +1,161 @@ -import './tagInput.less'; -import React, { useState, useEffect } from 'react'; -import _ from 'lodash'; +import "./tagInput.less"; +import React, { useState, useEffect, useMemo } from "react"; +import Combobox from "../../../components/combobox.jsx"; -const TagInput = ({ unique = true, values = [], ...props })=>{ - const [tempInputText, setTempInputText] = useState(''); - const [tagList, setTagList] = useState(values.map((value)=>({ value, editing: false }))); +import tagSuggestionList from "./tagSuggestionList.js"; - useEffect(()=>{ - handleChange(tagList.map((context)=>context.value)); +const TagInput = ({ label, unique = true, values = [], placeholder = "", onChange }) => { + const [tagList, setTagList] = useState( + values.map((value) => ({ + value, + display: value.trim(), + editing: false, + })), + ); + + // Keep in sync if parent updates values + useEffect(() => { + const incoming = values || []; + const current = tagList.map((t) => t.value); + + const changed = incoming.length !== current.length || incoming.some((v, i) => v !== current[i]); + + if (changed) { + setTagList( + incoming.map((value) => ({ + value, + display: value.trim(), + editing: false, + })), + ); + } + }, [values]); + + // Emit changes upward + useEffect(() => { + onChange?.({ + target: { value: tagList.map((t) => t.value) }, + }); }, [tagList]); - const handleChange = (value)=>{ - props.onChange({ - target : { value } + // Canonical duplicate groups + const duplicateGroups = [ + ["D&D", "DnD", "dnd", "Dnd", "dnD", "d&d", "d&D", "D&d"], + ["P2e", "p2e", "P2E", "Pathfinder 2e"], + ]; + + const normalizeValue = (input) => { + const group = duplicateGroups.find((grp) => grp.some((tag) => tag.toLowerCase() === input.toLowerCase())); + return group ? group[0] : input; + }; + + const regexPattern = /^[-A-Za-z0-9&_.()]+$/; + + const submitTag = (newValue, index = null) => { + const trimmed = newValue?.trim(); + if (!trimmed) return; + if (!regexPattern.test(trimmed)) return; + + const canonical = normalizeValue(trimmed); + + setTagList((prev) => { + const existsIndex = prev.findIndex((t) => t.value.toLowerCase() === canonical.toLowerCase()); + + if (unique && existsIndex !== -1) return prev; + + if (index !== null) { + return prev.map((t, i) => + i === index ? { ...t, value: canonical, display: canonical, editing: false } : t, + ); + } + + return [...prev, { value: canonical, display: canonical, editing: false }]; }); }; - const handleInputKeyDown = ({ evt, value, index, options = {} })=>{ - if(_.includes(['Enter', ','], evt.key)) { - evt.preventDefault(); - submitTag(evt.target.value, value, index); - if(options.clear) { - setTempInputText(''); - } - } + const removeTag = (index) => { + setTagList((prev) => prev.filter((_, i) => i !== index)); }; - const submitTag = (newValue, originalValue, index)=>{ - setTagList((prevContext)=>{ - // remove existing tag - if(newValue === null){ - return [...prevContext].filter((context, i)=>i !== index); - } - // add new tag - if(originalValue === null){ - return [...prevContext, { value: newValue, editing: false }]; - } - // update existing tag - return prevContext.map((context, i)=>{ - if(i === index) { - return { ...context, value: newValue, editing: false }; - } - return context; - }); - }); + const editTag = (index) => { + setTagList((prev) => prev.map((t, i) => ({ ...t, editing: i === index }))); }; - const editTag = (index)=>{ - setTagList((prevContext)=>{ - return prevContext.map((context, i)=>{ - if(i === index) { - return { ...context, editing: true }; - } - return { ...context, editing: false }; - }); - }); - }; - - const renderReadTag = (context, index)=>{ - return ( -
  • editTag(index)}> - {context.value} - -
  • - ); - }; - - const renderWriteTag = (context, index)=>{ - return ( - handleInputKeyDown({ evt, value: context.value, index: index })} - autoFocus - /> - ); - }; + const suggestionOptions = tagSuggestionList.map((tag) => ( +
    + {tag} +
    + )); return ( -
    - -
    -
      - {tagList.map((context, index)=>{ return context.editing ? renderWriteTag(context, index) : renderReadTag(context, index); })} +
      + {label && } + +
      +
        + {tagList.map((t, i) => + t.editing ? ( + { + const val = e.target.value; + setTagList((prev) => + prev.map((tag, idx) => (idx === i ? { ...tag, display: val } : tag)), + ); + }} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + submitTag(e.target.value, i); + } + }} + autoFocus + /> + ) : ( +
      • editTag(i)}> + {t.display} + +
      • + ), + )}
      - setTempInputText(e.target.value)} - onKeyDown={(evt)=>handleInputKeyDown({ evt, value: null, options: { clear: true } })} + { + submitTag(value, null); + }} + onEntry={(e) => { + // Allow free typing + Enter + if (e.key === "Enter") { + e.preventDefault(); + submitTag(e.target.value, null); + } + }} />
      diff --git a/client/homebrew/editor/tagInput/tagSuggestionList.js b/client/homebrew/editor/tagInput/tagSuggestionList.js new file mode 100644 index 000000000..ec0ff4f8e --- /dev/null +++ b/client/homebrew/editor/tagInput/tagSuggestionList.js @@ -0,0 +1 @@ +export default ["D&D", "P2e", "VtM", "CoC"]; From 1c35d08a5cb4b70d3a69b9afeba499f91d3afb97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Sun, 15 Feb 2026 20:40:41 +0100 Subject: [PATCH 02/11] stable version --- .../editor/tagInput/tagSuggestionList.js | 2003 ++++++++++++++++- 1 file changed, 2002 insertions(+), 1 deletion(-) diff --git a/client/homebrew/editor/tagInput/tagSuggestionList.js b/client/homebrew/editor/tagInput/tagSuggestionList.js index ec0ff4f8e..df2dfb7dc 100644 --- a/client/homebrew/editor/tagInput/tagSuggestionList.js +++ b/client/homebrew/editor/tagInput/tagSuggestionList.js @@ -1 +1,2002 @@ -export default ["D&D", "P2e", "VtM", "CoC"]; +export default [ + "meta:Theme", + "5e", + "Subclass", + "meta:theme", + "subclass", + "Class", + "Homebrew", + "Race", + "Dungeons and Dragons", + "theme", + "Daggerheart", + "2024", + "One Piece", + "One Piece DND", + "Luffy", + "Dungeons and Devil Fruits", + "Strawhats", + "Template", + "Campaign Frame", + "class", + "Players Handbook", + "dnd", + "osr", + "Dungeon Masters Guide", + "shadowdark", + "dragonbane", + "PHB", + "example", + "Devil Fruits", + "system:pf2e", + "DnD", + "DMG", + "system:dnd5.5", + "Monster", + "homebrew", + "race", + "template", + "Warlock", + "monster", + "Fighter", + "warlock", + "druid", + "sorcerer", + "D&D", + "Magic Item", + "Barbarian", + "Artificer", + "2014", + "system:descent into avernus", + "Sorcerer", + "Adventure", + "Paladin", + "Ranger", + "user help", + "fighter", + "5th Edition", + "Spells", + "Monk", + "Spell", + "NPC", + "Cleric", + "spell", + "Rogue", + "css", + "Item", + "artificer", + "magic item", + "Rules", + "barbarian", + "wizard", + "russian", + "DnD5e", + "Wizard", + "paladin", + "bastionland", + "spells", + "Devil Fruit", + "Bard", + "5.5e", + "rogue", + "Tabletop System", + "Haki", + "Druid", + "mystic bastionland", + "item", + "Lore", + "bard", + "monk", + "system:dnd5e", + "world", + "ranger", + "WIP", + "cleric", + "Dragon", + "Naruto", + "Creature", + "snippet", + "npc", + "DeS", + "Magic", + "guide", + "v3", + "Beast", + "Classe", + "onering", + "Monsters", + "Races", + "Weapon", + "adventure", + "Subclasses", + "stat block", + "weapon", + "Species", + "DONE", + "archetype", + "RPG", + "Hollow Knight", + "5e'24", + "Martial", + "DND", + "Classe Nova", + "Curse of Strahd", + "Boss", + "Hollowed Kingdoms", + "baldurs mouth", + "5.24", + "Homewbrew", + "Encyclopedia", + "Revised", + "OneWorldHD", + "knight", + "DPS", + "srd", + "Undead", + "items", + "DnD 5e", + "Guide", + "Compendium", + "Feat", + "newspaper", + "magic", + "TTRPG", + "descent into avernus", + "reference", + "system:D&D 5e24", + "feat", + "Magic Items", + "Campaign", + "resource", + "Feats", + "Anime", + "dd5", + "races", + "Monstrosity", + "DM Screen", + "2024 Rules", + "Rework", + "Character Build", + "Done", + "5e 2024", + "Construct", + "myth", + "magic items", + "creature", + "Legendary", + "Strahd", + "background", + "Player", + "style", + "Legacy", + "Player Handbook", + "martial", + "Character", + "Dungeons & Dragons", + "Table", + "reddit", + "monsters", + "OneDND", + "dragon", + "Suporte", + "Soulbound", + "Expanded Handbook", + "bestiary", + "Humanoid", + "system:dnd", + "Oredell", + "system:class", + "V3", + "system:5e", + "5e'14", + "Age of Sigmar", + "Items", + "Eberron", + "horror", + "dnd5e", + "star wars", + "Background", + "compendium", + "revision", + "Elemental", + "character", + "Marcial", + "SW5e", + "notes", + "DM", + "Fey", + "one-shot", + "resources", + "NEW", + "campaign", + "wondrous item", + "Setting", + "Archive", + "NIMRE", + "Tanque", + "Jogavel", + "Dnd 5e", + "LotM", + "setting", + "revised", + "Warhammer", + "rework", + "Conjurador", + "GMBinder", + "ItemSet", + "NPCs", + "classes", + "CR 2", + "AetherSail", + "undead", + "Artifact", + "cards", + "Example", + "Guides", + "Theme", + "Swamp", + "CR 1", + "patron", + "Extra", + "concept", + "final fantasy", + "Aberration", + "Elder Scrolls", + "rules", + "meta:gratis", + "Dice Pool", + "Cue", + "dark", + "type:Style", + "rpg", + "meta:free", + "summoner", + "OC", + "rare", + "Fleshing Out", + "francais", + "Dnd", + "Creatures", + "Sims 4", + "sous-classe", + "ffxiv", + "Underdark", + "add-on", + "weapons", + "Subrace", + "dungeons and dragons", + "Naruto 5e", + "Lafari", + "Very Rare", + "d6", + "red", + "Equipment", + "CR 3", + "Patron", + "5E", + "objet magique", + "spellcaster", + "feats", + "5.24e", + "system:d&d5e", + "Rare", + "Thudnfer", + "daggerheart", + "CR 1/2", + "Archetype", + "dnd 5e", + "Pathfinder", + "lineage", + "Celestial", + "Support", + "species", + "ARCHIVED", + "Horror", + "humanoid", + "Subclase", + "book:PHB E&E", + "final fantasy xiv", + "Jungle", + "Feywild", + "Fiend", + "subclasses", + "HB", + "Legacy Challenge", + "Project Horizon", + "vampire", + "WoW", + "DND 5e", + "Weapons", + "system:book clone", + "CoS", + "N5e", + "Summon", + "Spellcaster", + "Koretra", + "Voidborn", + "one shot", + "Templates", + "tables", + "Iphexar", + "Shattered Obelisk", + "Sword Coast", + "elemental", + "lore", + "character sheet", + "discord", + "BetterMonsters", + "players", + "group:simple skans", + "Coastal", + "Forest", + "Unearthed Arcana", + "Old", + "Collection", + "Ancestry", + "Caevash", + "Strixhaven", + "Limbus Company", + "Daydreams & Deviants", + "Statblocks", + "Urban", + "Classes", + "familiar", + "Blood", + "oneshot", + "n5e", + "wip", + "masks", + "Planeshifted", + "Carrioss", + "avernus", + "object", + "1", + "Ruins", + "Anime Character", + "wild shape", + "mask", + "dj9 game", + "Handbook", + "Curse", + "oath", + "Midralis", + "Appendix", + "5.5", + "tales of the valiant", + "player classes", + "Caster", + "Large", + "Fateforge", + "Cursed", + "beast", + "Pathfinder 2e", + "Design", + "Uncommon", + "Endeur", + "Elemental Water", + "SCC", + "sci-fi", + "Dragons", + "human", + "Gods", + "Medium", + "System", + "Help", + "Handout", + "Skyrim", + "BnB", + "draft", + "PC", + "Variant", + "syntax", + "OneShot", + "Clase", + "UESTRPG", + "Savannah", + "Reef", + "CR 5", + "Forgotten Realms", + "collection", + "Combat", + "Historia", + "artifact", + "Expansion", + "Attunement", + "Variant Rules", + "d&d", + "Party Build", + "Evocation", + "homerule", + "Forbidden West", + "how-to", + "tov", + "Mystical Item", + "CR 4", + "Necromancer", + "General Rules", + "Needs Update", + "stat blocks", + "DC Comics", + "Sword", + "Armor", + "blood hunter", + "Blood Hunter", + "Meio Conjurador", + "Mydia", + "3rd Party", + "N5E", + "Delvebound", + "Ocean", + "Subterranean", + "half-caster", + "Demon", + "Fire", + "meta:Template", + "Character Sheet", + "PF2e", + "png", + "fantasy", + "Setting Guide", + "Style", + "Cor", + "legacy", + "Minion", + "meta:khaoz age", + "Book", + "magical item", + "immersion", + "reminder cards", + "Regras", + "Durnovar", + "2025", + "Camp1", + "Abyss", + "armor", + "construct", + "firearms", + "Backgrounds", + "Companion", + "Melee", + "fey", + "Incomplete", + "Vampire", + "Bestiary", + "Worldbuilding", + "History", + "Conjuration", + "necromancy", + "dragons", + "ancestry", + "Mech", + "PbtA", + "COS", + "One Shot", + "Factions", + "Transmutation", + "Spellcasting", + "card", + "Ardh", + "redveil", + "conditions", + "elturel", + "rhye", + "group:James Haeck", + "CaelYuu", + "system:5.24e", + "system:GM Binder", + "Grassland", + "melee", + "Potions", + "anime", + "D&D 5e", + "Healer", + "Gambling", + "Lightning", + "fighting style", + "support", + "Style Template", + "mtg", + "NSFW", + "aventura", + "Manuals", + "plant", + "Incarnate", + "Crafting", + "DnDBeyond", + "Monster Girl", + "Monster Girl Encyclopedia", + "pet", + "npcs", + "Stat Block", + "Styleguide", + "mitologia", + "Objeto maravilloso", + "vaesen rpg", + "dnd-2024", + "Class Handbook", + "Space", + "Taiga", + "CR 6", + "Pact Boon", + "race/ancestry", + "Necromancy", + "cantrip", + "LoL", + "Raza", + "handout", + "Mechanic", + "Conversion", + "Wondrous Item", + "Familiar", + "necromancer", + "uncommon", + "curse", + "Campaign Setting", + "Tetra", + "1e", + "module", + "Evolving", + "boiling sea", + "deck", + "OSR", + "RU", + "VL", + "Underdeep", + "Deep Ocean", + "Giant", + "statblock", + "combat", + "Time", + "5E24", + "session zero", + "elf", + "tank", + "sorcerous origin", + "Drakkenheim", + "Tavern", + "Domain", + "healer", + "Valenor", + "blood", + "Oath", + "spooky", + "fire", + "meta:5e24 Style", + "Notes", + "City", + "Conjurador Completo", + "prop", + "Dotherys", + "Rietuma 3.0", + "5e24", + "Library of Ruina", + "español", + "Project Echo", + "battle of Japan", + "Plant", + "Badlands", + "Neverwinter", + "Fantasy", + "Beastfolk", + "Unarmed", + "Cold", + "Damage", + "attunement", + "Hurthud", + "3rd Level", + "spelljammer", + "mostro", + "Custom", + "PT-BR", + "Alternative Realms", + "The Foot", + "boss", + "demo", + "Supplement", + "FitD", + "classe", + "5.14", + "Copy", + "DnD5e24", + "X-Men", + "TNA", + "CR 8", + "Desert", + "CR 7", + "arme", + "random", + "spellcasting", + "Deprecated", + "Cards", + "finished", + "Ben 10", + "equipment", + "Geography", + "Games", + "For Players", + "Faerun", + "scroll", + "Faction", + "Alchemist", + "drow", + "Lineage", + "mix-blend-mode", + "columns", + "User Help", + "Reami Dimenticati", + "Класс", + "D100", + "nsfw", + "hucaen", + "v1.0", + "Cortex", + "Fallout", + "ww5e", + "MAGIC", + "DnD2024", + "ToV", + "D&D2024", + "The Backrooms", + "Freshwater", + "D20", + "Dragonborn", + "custom", + "sword", + "Dungeons and Dragons 5e", + "Water", + "legendary", + "Dungeon", + "Ravenloft", + "aberration", + "Longsword", + "transmutation", + "Fairy Tail", + "Character background", + "Exandria", + "Updated", + "pitch", + "Half-Caster", + "Complete", + "Money", + "player", + "forgotten-realms", + "Festival", + "Casino", + "SCAG", + "Currency", + "North", + "Toril", + "Scourged Land of Valenor", + "Oota", + "parchment", + "Literature", + "Serrith", + "PNJ", + "Divinity Original Sin 2", + "Wild", + "videogame", + "magic the gathering", + "sweetblossom", + "GMscreen", + "MandM", + "D&D 5.24", + "Camp2", + "Remaster", + "riassunti", + "type:Resource", + "system:D&D", + "tag:Class", + "Excelsior", + "Stat Blocks", + "Sci-Fi", + "Ooze", + "CR 1/8", + "sublclass", + "chart", + "Mountains", + "guns", + "Nature", + "Orc", + "Poison", + "Devil", + "fiend", + "DC", + "pt-br", + "ABnB", + "One-Shot", + "strahd", + "Ring", + "Theme song", + "orc", + "summon", + "Psion", + "Psionics", + "Dungeon Master", + "vehicle", + "DM only", + "Demigod", + "Antica Energia", + "Pirates", + "Sourcebook", + "devil", + "Cantrip", + "mystery", + "MtG", + "conversion", + "Festivals", + "Casinos", + "Taverns", + "Betting", + "Drinking", + "phandelver", + "Warhammer 40k", + "mutant", + "styling", + "FATE", + "Lone Wolf", + "icon", + "New Dawn", + "Magic Set", + "Paladin Subclass", + "Alter Class", + "difficulty classses", + "combat tables", + "phb", + "Project Moon", + "Undertomes", + "EGO", + "Campagne 1", + "Constelação", + "Arvore I", + "Fim da Jornada", + "greek god", + "-1 OR 5*5=25 --", + "-1 OR 5*5=26 --", + "-1 OR 5*5=25", + "-1 OR 5*5=26", + "-1' OR 5*5=25 --", + "-1' OR 5*5=26 --", + "-1\" OR 5*5=25 --", + "-1\" OR 5*5=26 --", + "1*if(now()=sysdate(),sleep(15),0)", + "10'XOR(1*if(now()=sysdate(),sleep(15),0))XOR'Z", + "10\"XOR(1*if(now()=sysdate(),sleep(15),0))XOR\"Z", + "(select(0)from(select(sleep(15)))v)/*'+(select(0)from(select(sleep(15)))v)+'\"+(select(0)from(select(sleep(15)))v)+\"*/", + "1-1; waitfor delay '0:0:15' --", + "1-1); waitfor delay '0:0:15' --", + "1-1 waitfor delay '0:0:15' --", + "1*DBMS_PIPE.RECEIVE_MESSAGE(CHR(99)||CHR(99)||CHR(99),15)", + "1'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(98),15)||'", + "'\"", + "����%2527%2522\\'\\\"", + "(select 198766*667891)", + "(select 198766*667891 from DUAL)", + "dwarf", + "Firearms", + "3.5e", + "generator", + "Elf", + "meta: Scenario", + "enchantment", + "buff", + "ITW", + "Tank", + "Archived", + "Martial Archetype", + "caster", + "BR", + "Knight", + "Utility", + "SWADE", + "Star Wars", + "pc", + "Mystic", + "Useful", + "Netherdeep", + "crafting", + "Sapient Undead", + "Maverick", + "Revision", + "Resource", + "Humblewood", + "one piece", + "Bag of Holding", + "medium", + "lightning", + "backgrounds", + "4th Level", + "path", + "BREAK-RPG", + "dark fantasy", + "Players", + "poison", + "psionic", + "gazook89", + "homebrew subclass", + "wild-wasteland", + "CWD", + "Paid", + "Tales of the Valiant", + "Dreadhold", + "arma", + "system:Mutants and Masterminds", + "#Tiefschlaf", + "Brew", + "Myra", + "Swashbuckler", + "dead by daylight", + "Exceptional", + "COD Zombies", + "Hills", + "Tundra", + "type:Campaign", + "wild magic", + "Food", + "Death", + "homebrew rules", + "Remake", + "Witcher", + "water", + "Pet", + "book", + "AAH", + "pact", + "Ice", + "Character Creation", + "animal", + "Pokemon", + "clase", + "5e14", + "DBZ", + "CLONE", + "Evil", + "Tarsere", + "Mythology", + "pf2e", + "Magical", + "type:race", + "Sorcerous Origin", + "Information", + "styles", + "Module", + "gish", + "frames", + "DeltaGreen", + "Magic item", + "food", + "chef", + "basics", + "giant", + "Brew Creation", + "One-shot", + "ttrpg", + "Path", + "Don't Starve", + "MGE", + "firearm", + "DnDBehindTheScreen", + "store", + "The Artisan", + "timeline", + "college", + "dev", + "dungeon of the dead three", + "Cradle", + "Dnd5e", + "dungeon", + "Amaranthine", + "Regno di Oltremare", + "bestia", + "rewrite", + "WiP", + "Subclasse", + "mutants and masterminds", + "The Embrace", + "meta:documentation", + "Mutants And Masterminds", + "khedoria", + "Encounter Pack", + "giorni", + "Statblock", + "Enemies", + "Goblinoids", + "Heavens", + "system:2e", + "Vaalbara", + "Dwarf", + "airos", + "table", + "Artificer Specialization", + "Buff", + "Book 1", + "Ranged", + "cypher", + "utilities", + "40k", + "Psychic", + "Fear", + "steampunk", + "shadow", + "subclase", + "Barbarian Subclass", + "Elements", + "pact boon", + "Clan", + "Fly", + "solo", + "sourcebook", + "Marvel Comics", + "compilation", + "Firearm", + "sidekick", + "infusions", + "Mechanics", + "Summoner", + "Aasimar", + "Human", + "Vehicle", + "Shadow", + "Clone", + "custom css", + "ocean", + "sotdl", + "bandit", + "Wind", + "Printer Friendly", + "Obsolete", + "mechanics", + "illusion", + "5th edition", + "League of Legends", + "Vestige", + "dungeons", + "Dungeons", + "and", + "Elden Ring", + "L5R", + "d20", + "Poisons", + "d15", + "Dungeons And Dragons", + "MTG", + "divine", + "characters", + "witch", + "Anime Homebrew", + "Zombie", + "thunder", + "Jujutsu Kaisen", + "campagne", + "Deadlands", + "spell list", + "1 Person", + "Ritual", + "screen", + "nature", + "Divination", + "Compattare", + "dtrpg", + "quick ref", + "Mago", + "Illivia", + "Shonen", + "Core Deities", + "green ronin", + "Bless", + "D&D5e", + "version:0.1.0", + "curato", + "system:Ord", + "Images", + "Sealed Artifact", + "Giants", + "CR 9", + "CR 11", + "CR 0", + "CR 14", + "Shadowfell", + "Tier 1", + "d100", + "Elemental Air", + "artificiel", + "Cultist", + "Cyberpunk", + "Huge", + "Warrior", + "Gun", + "quest", + "LYRA", + "Music", + "Tiefling", + "Master", + "Witch", + "Linnorm", + "1st-level", + "Mount", + "Animal", + "Comics", + "Superhero", + "creatures", + "Hunter", + "Control", + "Dragon Ball", + "Dragon Ball Z", + "Dagger", + "questingforamonster", + "ICRPG", + "Booklet", + "f and t", + "common", + "Chaos", + "spellblade", + "Constitution", + "artisan", + "arcane", + "Released", + "ring", + "runes", + "gun", + "Supportive Material", + "The Witcher", + "Desarmado", + "Monster Monday", + "Bleach", + "Demon Slayer", + "mice", + "worldbuilding", + "Necrotic", + "ability score", + "demon", + "Armybook Shivatiano", + "warrior", + "Fighter Subclass", + "system", + "whisperveil", + "psychic", + "warhammer", + "Aventura", + "Culture", + "Material", + "meta:npc", + "shops", + "magic weapon", + "nhera", + "Dark Fantasy", + "Regles", + "Wonderous Item", + "Features", + "pokemon", + "Ghosts of Saltmarsh", + "monstrosity", + "DL TWW", + "companion", + "alternate layout", + "Tutorials", + "Kitsune", + "don", + "heroique", + "mini campaign", + "drago", + "Aquatic", + "tool", + "handmade", + "released", + "Spellblade", + "pregen", + "level 2", + "Baldurs gate 3", + "My Hero", + "Technically a subclass", + "5.24e Remastered Subclasses", + "dinosaurs", + "5E.2024", + "Razas", + "Horizon", + "Clothing", + "+2", + "castellano", + "pentacle prophecy", + "tag:Spells", + "gruppo A", + "Rpg", + "razze", + "type:Adventure", + "unfinished", + "3.5", + "gunslinger", + "BBEG", + "Arcane", + "component", + "Bow", + "backstory", + "phandalin", + "Skills", + "Pact", + "Elemental Earth", + "Joke", + "invocation", + "martial class", + "Super Villain", + "Eldritch", + "Elemental Fire", + "Homebrew Class", + "eldritch", + "cyberpunk", + "Player Race", + "Class Mod", + "Heatcoast", + "meta:Guide", + "Yemao", + "evil", + "Named NPC", + "CLASS", + "Angel", + "vecna", + "PT", + "PTBR", + "Ancient", + "Small", + "WotC Style", + "5e Homebrew", + "1st Level", + "dagger", + "Brancalonia", + "encounter", + "cat", + "primal path", + "Ambientazione", + "Magie", + "candlekeep", + "Ongoing", + "Oneshot", + "Wondrous", + "Janbrewery", + "Tattoos", + "5e (2014)", + "concentration", + "very rare", + "Set", + "Kobold", + "martial archetype", + "God", + "blog", + "New Gate", + "Healing", + "OneDnD", + "Incantesimi", + "Player Options", + "contest", + "pirate", + "Manuel", + "Alchimie", + "Herboristerie", + "Ingredients", + "starlost", + "Campaign 1", + "Abandoned", + "Previous Editions", + "Enchantment", + "Tools", + "Oblivion", + "domain", + "5th Level", + "DnD Beyond", + "Reference", + "Sorcerer Subclass", + "Dragon Magazine", + "feature", + "german", + "conjuration", + "strixhaven", + "Sentient", + "JJK", + "10 Generations", + "character creation", + "LevelUp", + "pallid grove", + "primer", + "Requires Attunement", + "College", + "Aesthetic", + "critter", + "home game", + "spanish", + "stats", + "Lairon", + "Hunters Guild", + "original setting", + "Bosses", + "Radiant Citadel", + "actions", + "Reworked", + "Elystera", + "Wyvern", + "vikings", + "thief", + "enemies", + "Obsession", + "Yi Sang", + "aberrazione", + "Limbus", + "animals", + "minecraft", + "mice of legend", + "osric", + "20 Minutes Till Dawn", + "campaign frame", + "latigo", + "DH", + "Eldritch Invocation", + "system:daggerheart", + "100ni", + "meta:Sheet", + "fa-solid fa-sheet-plastic:Ficha", + "tag:Berean", + "AD&D", + "B/X", + "The Codex Of Anomalous Entities", + "monster manual", + "Polar Waters", + "CR 12", + "CR 10", + "blood magic", + "Gunslinger", + "grimoire", + "Drakes", + "Japanese", + "subrace", + "ooze", + "Stats", + "Half Caster", + "Sea", + "time", + "Brawler", + "Session 0", + "Halloween", + "Runeterra", + "Divine", + "Random", + "Lifestar", + "arcane trickster", + "Paddy4530", + "evocation", + "light", + "Steampunk", + "shaman", + "Primal Path", + "monk subclass", + "Full Caster", + "World", + "Planning", + "spirit", + "Nova Era", + "abjuration", + "Christmas", + "Critical Role", + "Gish", + "Bandit", + "Monster Manual", + "party member", + "mgazt", + "Playable Race", + "Donjon.bin.sh", + "Final Fantasy", + "Roleplay", + "monstre", + "fairy", + "frame", + "Minecraft", + "Stealth", + "Manual", + "half caster", + "Storm", + "Sorcery", + "format work", + "Kingdom Hearts", + "hexblade", + "block", + "page layouts", + "Monk Subclass", + "FinyaFluKaiKolja", + "Radiant", + "group:playtest", + "Korrahir", + "noble", + "exorcist", + "xapien", + "Raven Queen", + "markdown", + "damage", + "Alchemy", + "morrigan", + "genasi", + "ZNH", + "folklore", + "Fate", + "hechicero", + "Air", + "Magic Weapon", + "Anime DND 5e", + "Dragon Ball Z TTRPG", + "Dragon Ball Z RPG", + "Dragon Ball Z DND", + "Dragon Ball Z 5e", + "samurai", + "Goblin", + "Base Sheet", + "Shackled City Adventure Path", + "Natureza", + "control", + "Normarch", + "Reddit", + "Genshin Impact", + "Abjuration", + "Myr", + "Flight", + "Vampyre", + "nightmare", + "Lycan", + "Occult", + "circle", + "Christmas Special", + "DoDD", + "Character Options", + "traduction", + "Characters", + "Gear", + "system:sf2e", + "drakkenheim", + "downtime", + "v1.1", + "amulet", + "Feiticeiros e Maldicoes", + "Tecnica amaldicoada", + "prorpg", + "enemy", + "No Mercy", + "rain world", + "slugcat", + "fly", + "meta:User Guide", + "Fallout TTRPG", + "regles", + "Ill Tides", + "Light-hearted", + "Vastria", + "school", + "Fillible Online", + "Mezgarr", + "Berserk", + "invocations", + "Classe Refeita", + "Auroboros", + "bosses", + "fabula ultima", + "Shagya", + "wild", + "DnD 2024", + "KaiburrKathHound", + "Barbarian Path", + "fauna", + "5E.2014", + "system:curse of strahd", + "Unofficial", + "how to", + "Glaive", + "A5E", + "pt", + "Consumible", + "Realmers'", + "Versatile Lineage", + "Shichibukai", + "2024e", + "Rencontre", + "tag:Spell List", + "elementalist", + "noncaster", + "blasphemous", + "Mordhiem", + "Wildfrost", + "#Regelwerk", + "Rewrite", + "Maldición de Strahd", + "Scion", + "Entities", + "Hoarwyrm", + "Player utility", + "CR 1/4", + "Temperate Forest", + "Demons", + "Drow", + "type:rules", + "fay", + "2e", + "familier", + "supplement", + "Amberwar", + "slime", + "Lycanthropy", + "meta: Terres de Leyt", + "Strong", + "AAH Vol. 1", + "Force", + "Jump", + "Aboleths", + "lol", + "location", + "small", + "customizable", + "Modern", + "Sky", + "portugues", + "Hero", + "Villain", + "element", + "Tyranny of Dragons", + "Adventure Guide", + "New Class", + "Witchlight", + "Shardblade", + "Plateaux", + "WOTC", + "Snippet", + "Terra", + "Otherworldly Patron", + "ritual", + "hag", + "Cyberpunk 2077", + "tavern", + "Artificer Specialist", + "Werewolf", + "Boesia", + "vampiric", + "monastic tradition", + "Gothic", + "celestial", + "Unfinished", + "Core", + "Arcane Tradition", + "Troll", + "Origin", + "Draconic", + "dj9 member", + "test", + "Hag", + "gem", + "Invocations", + "Dark Sun", + "aarkhen", + "How to", + "ravenloft", + "faerie", + "Playtest", + "Shaman", + "dead", + "Tomba Aniquilacio", + "Pacto", + "fullcaster", + "Electric", + "Ability Score", + "4D", + "pathfinder", + "insect", + "hook", + "page layout", + "healing", + "Lineages", + "Flying", + "Martial Arts", + "journal", + "Aide de jeu", + "hunter", + "headers", + "Dark Souls", + "courtyard", + "crossroads", + "Quest", + "CotF", + "defense", + "Semryss", + "invoked class", + "Session Notes", + "goblin", + "infernal", + "fate", + "oni", + "spellbook", + "Summoning", + "slut", + "whore", + "Greyhawk", + "Mobility", + "Reddit Remake", + "Guild", + "Cosmic Mart", + "7th Level", + "dragonborn", + "curse of strahd", + "Ranger Subclass", + "dossier", + "dossie", + "de", + "pnpde", + "Plane Shift", + "halloween", + "group:aventura", + "9th Level", + "tome", + "cold", + "acid", + "deprecated", + "mind flayer", + "MECHA", + "EssentialsKit", + "2d6", + "ToD", + "Work In Progress", + "Bond", + "Versatile", + "Dead", + "SYWTBAGM", + "summoning", + "english", + "Eilistraee", + "Draft", + "DoD", + "map", + "Frightened", + "Psychic Damage", + "eberron", + "recompensa", + "wizard subclass", + "teiran", + "Saltmarsh", + "jp setting", + "Illithid", + "Longbow", + "hell", + "Monarch", + "type:feat", + "reglas", + "cooking", + "Abenteuer", + "reloaded", + "incompleto", + "mecanica", + "Location", + "Grimlores Grimoire", + "2024 Subclass", + "Chiesa di Toleno", + "finalfantasy", + "The Undertomes", + "Lobotomy Corporation", + "SDHTA", + "D&D 2024", + "other", + "ally", + "images", + "Player's Guide", + "Avalon Sword", + "Cael'Yuu", + "dnd-2014", + "Regelwerk", + "Español", + "br", + "dnd 5.0", + "monstro", + "grand cemetery", + "Phoenix", + "dnd 2024", + "Bloodhunter", + "Sintonizacion", + "dungeons & dragons", + "Fix", + "Rulebook", + "Shadowdark", + "heroic", + "HFW", + "Earthdawn", + "24e", + "cormyr", + "suzail", + "dc20", + "tag:Rules", + "The Griffon's Saddlebag", + "LOTM", + "tag:Adventure", + "drunken master", + "eldritch invocation", + "Персонаж", + "Orcs", + "Lizardfolk", + "Frostfell", + "CR 17", + "Shapechanger", + "Farmland", + "Mages", + "Any", + "CR 13", + "Earth", + "Mountain", + "Drake", + "transformation", + "GM", + "Lich", + "lovecraft", + "unique", + "Optional Rules", + "int", + "creator", + "Primal", + "simple", + "golem", + "Void", + "Armour", + "spellsword", + "General", + "Asian", + "Bringers of chaos", + "Optional Feature", + "subraces", + "Galanoth", + "barbarian subclass", + "felhearth", + "modular", + "Vampires", + "wysteria", + "adaptation", + "beasts", + "naruto", + "ninja", + "Psionic", + "Guns", + "Crystal", + "Guardian", + "NonProfit", + "Mimic", + "languages", + "Epic Boons", + "Primer", + "Icewind Dale", + "joke", + "lycan", + "CR3", + "Armors", + "ff7", + "materia", + "final fantasy 7 remake", + "esper", + "ff7 remake", + "gargantuan", + "Frog", + "CR5", + "blank", + "monster hunter", + "league of legends", + "french", + "Pokémon", + "kobold", + "soul", + "ffxi", + "d10", + "Roman", + "Cute", + "DD5", + "variant", + "tree", + "fr", + "Scenario", + "lycanthrope", + "druide", + "staff", + "eios", + "arkheneios", + "Runic", + "Work", + "Ukrainian", + "cover-page", + "mage", + "deities", + "gods", + "Boss Fight", + "Lair", + "WBTW", + "roguish archetype", + "Character Option", + "Shortsword", + "Illrigger", + "Bloodborne", + "cr6", + "Priest", + "Hamon", + "Toonkind", + "rol", + "Strength", + "forgotten realms", + "Spanish", + "Conclave", + "Electro", + "Magical Tattoos", + "Matt Mercer", + "Wildemount", + "Mighty Nien", + "Campaign 2", + "Resistances", + "Bug", + "impression", + "PF", + "Magnus Archives", + "ice", + "speed", + "Generic NPC", + "Titanic", + "Ink Friendly", + "bleed", + "elder scrolls", + "Immortal", + "LMOP", + "Travel", + "Olphus", + "3d6", + "heist", + "World History", + "ghost", + "genie", + "kids on bikes", + "Russia", + "conclave", + "overhaul", + "manual", + "Adventures In Eden", + "Downtime", + "hamon", + "cloak", + "shadowfell", + "Hellfire", + "Paladin Oath", + "Genshin", + "Nation", + "air", + "Magical Item", + "War", + "Original", + "Monstrous Compendium", + "Calamity", + "Warden", + "Apocalypse", + "shield", + "AC", + "expansion", + "Concentration", + "charm", + "Weave", + "lycanthropy", + "raza", + "far realm", + "fighter subclass", + "ita", + "Pirate", + "Laranja", + "Grapple", + "EastByForce", + "hobgoblin", + "oneshot-notes", + "Holy", + "optional", + "type:cenario", + "group:core", + "The Brewery", + "Alcance", + "Morrowind", + "Indigo", + "Divino", + "2nd Level", + "Sub-Class", + "cantrips", + "Cloak", + "battle master", + "Dark", + "Puzzle", + "Lucky", + "consumable", + "rebalance", + "Shove", + "Area Control", + "Vanguard", + "funny", + "e5", + "Dragonlance", + "psion", + "initiative", + "Tactician", + "Inspiration", + "artificier", + "way", + "inspired", + "historia", + "Medusa", + "2 part", + "holy", + "gift", + "Nimble", + "mostri", + "phoenix", + "travel", + "Class Template", + "Intimidation", + "constructs", + "P666", + "Formatting", + "Divinity", + "Rod", + "Language", + "yokai", + "rune", + "western", + "vampires", + "flying", + "cute", + "Enemy", + "boon", + "Tables", + "ShadowFight", + "meta: Theme", + "SCS", + "vanthampur villa", + "CoA", + "shop", + "destiny", + "magical weapon", + "Arcane Arcade", + "XP to Level 3", + "Dice Average RPG", + "Pip-Boy", + "Dragon Heist", + "session notes", + "tattoo", + "flick", + "P6:66", + "Comic Character", + "experiment", + "Minerva", + "type:Spellbook", + "Realmfall", + "Wand", + "halfling", + "sw5e", + "implementar AP", + "Mask", + "Gazook89", + "Weltenrauch-Chroniken", + "MiA", + "Made in Abyss", + "français", + "fae", + "Lemuria", + "Mork Borg", + "guerrier", + "prunus", + "condition", + "pf2", + "tr", + "costrutto", + "German", + "project moon", + "5r", + "galles", + "Project moon", + "Yisang", + "Spicebush", + "player-accessible", + "Especie", + "Westmarch", + "a", + "Cart", + "Magus", + "group:Mchael Galvis", + "tip", + "werewolf", + "mundane", + "garrett", + "unarmed", + "Arcane Odyssey", + "Tomb of Divinity", + "pets", + "Video Game", + "4 part", + "pbta", + "Druids", + "multiclass", + "manuale", + "mimic", + "plane shift", + "Dotes", + "Hechizos", + "Infernal", + "Enhanced", + "done", + "Mission report", + "Blanks", + "Masks", + "Ultimate Ability", + "shadow-slave", + "Advertising", + "transform", + "Fullmetal Alchemist", + "Fullmetal Alchemist Brotherhood", + "tag:TAoF&F", + "Dwarves", + "Humans", + "Nine Hells", + "Devils", + "Archons", + "CR 15", + "Troglodytes", + "Goliath", + "retired", + "boots", + "ranged", + "shields", + "Zhentarim", + "World of Warcraft", + "Frontline", + "Guildmaster's Guide to Ravnica", + "Dungeons & Dragons 5e", + "beholder", + "NEEDS FIXING", + "mechanic", + "Loot", + "champion", + "Runes", + "Shield", + "Punch", + "Sniper", + "Magical Girl", + "NotDND", + "story", + "Sleep", + "Bard College", + "Illusion", + "Thunder", + "Defender", + "Genasi", + "troll", + "Gehenna", + "Yugoloth", + "social", + "Player Class", + "homebrew class", + "CR 16", + "Ghost", + "Kobolds", + "Trolls", + "Yuan-Ti", + "Elder Scrolls Offline", + "armure", + "Mage", + "CR 18", + "Technology", + "Mystery", + "darkness", + "Airship", + "New Campaign", + "Warframe", + "Wizard Subclass", + "Gold", + "Candor", + "Overhaul", + "Dragon Knight", + "Enoreth", + "Artifacts", + "New", + "AMMO", + "Campagne", + "Valbise", + "Subclasseptember", + "Mecha", + "Yu-Gi-Oh", + "Goblinoid", + "underwater", + "SW5E", + "bardo" +] \ No newline at end of file From 8cdc5ab0afc9acc1bb3f0fce1f721e909cf02bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Sun, 15 Feb 2026 23:40:41 +0100 Subject: [PATCH 03/11] curate suggestion and add in some color --- .../editor/metadataEditor/metadataEditor.less | 2 +- .../tagInput/curatedTagSuggestionList.js | 341 ++++++++++++++++++ client/homebrew/editor/tagInput/tagInput.jsx | 50 ++- client/homebrew/editor/tagInput/tagInput.less | 18 + .../editor/tagInput/tagSuggestionList.js | 22 -- 5 files changed, 399 insertions(+), 34 deletions(-) create mode 100644 client/homebrew/editor/tagInput/curatedTagSuggestionList.js diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index df915a546..83c0212ca 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -117,7 +117,7 @@ &.tags .tagInput-dropdown { z-index : 201; - max-width : 150px; + max-width : 200px; } } diff --git a/client/homebrew/editor/tagInput/curatedTagSuggestionList.js b/client/homebrew/editor/tagInput/curatedTagSuggestionList.js new file mode 100644 index 000000000..5df33db00 --- /dev/null +++ b/client/homebrew/editor/tagInput/curatedTagSuggestionList.js @@ -0,0 +1,341 @@ +export default [ + // ############################## Systems + // D&D + "system:D&D Original", + "system:D&D Basic", + "system:AD&D 1e", + "system:AD&D 2e", + "system:D&D 3e", + "system:D&D 3.5e", + "system:D&D 4e", + "system:D&D 5e", + "system:D&D 5e 2024", + "system:BD&D (B/X)", + "system:D&D Essentials", + + // Other Famous RPGs + "system:Pathfinder 1e", + "system:Pathfinder 2e", + "system:Vampire: The Masquerade", + "system:Werewolf: The Apocalypse", + "system:Mage: The Ascension", + "system:Call of Cthulhu", + "system:Shadowrun", + "system:Star Wars RPG (D6/D20/Edge of the Empire)", + "system:Warhammer Fantasy Roleplay", + "system:Cyberpunk 2020", + "system:Blades in the Dark", + "system:Daggerheart", + "system:Draw Steel", + "system:Mutants and Masterminds", + + // ###################################### RPG Keywords + + // Meta + "meta:Template", + "meta:Theme", + "meta:free", + "meta:Character Sheet", + "meta:Documentation", + "meta:NPC", + "meta:Guide", + "Resource", + "notes", + "syntax", + "example", + "stat block", + "Character Sheet", + + // Classes / Subclasses / Archetypes + "Class", + "Subclass", + "Archetype", + "Martial", + "Half-Caster", + "Full Caster", + "Artificer", + "Barbarian", + "Bard", + "Cleric", + "Druid", + "Fighter", + "Monk", + "Paladin", + "Rogue", + "Sorcerer", + "Warlock", + "Wizard", + + // Races / Species / Lineages + "Race", + "Ancestry", + "Lineage", + "Aasimar", + "Beastfolk", + "Dragonborn", + "Dwarf", + "Elf", + "Goblin", + "Half-Elf", + "Half-Orc", + "Human", + "Kobold", + "Lizardfolk", + "Lycan", + "Orc", + "Tiefling", + "Vampire", + "Yuan-Ti", + + // Magic / Spells / Items + "Magic", + "Magic Item", + "Magic Items", + "Wondrous Item", + "Magic Weapon", + "Artifact", + "Spell", + "Spells", + "cantrip", + "cantrips", + "Eldritch", + "Eldritch Invocation", + "invocation", + "Invocations", + "pact boon", + "Pact Boon", + "Spellcaster", + "spellcaster", + "Spellblade", + "Magical Tattoos", + "Enchantment", + "Enchanted", + "Attunement", + "Requires Attunement", + "Rune", + "Runes", + "Wand", + "Rod", + "Scroll", + "Potion", + "Potions", + "Item", + "Items", + "Bag of Holding", + + // Book type + "type:Campaign", + "type:Campaign Setting", + "type:Adventure", + "type:One-Shot", + "type:Setting", + "type:World", + "type:Lore", + "type:History", + "type:Dungeon Master", + "type:Encounter Pack", + "type:Encounter", + "type:Session Notes", + "type:reference", + "type:Handbook", + "type:Manual", + "type:Manuals", + "type:Compendium", + "type:Bestiary", + + // Monsters / Creatures / Enemies + "Monster", + "Creatures", + "Creature", + "Beast", + "Beasts", + "Humanoid", + "Undead", + "Fiend", + "Aberration", + "Ooze", + "Giant", + "Dragon", + "Monstrosity", + "Demon", + "Devil", + "Elemental", + "Construct", + "Constructs", + "Boss", + "BBEG", + + // ############################# Document meta tags + + "meta:v3", + "meta:Legacy", +]; + +const ReadList = [ + // Systems / Editions + "5e", + "5th Edition", + "5.5e", + "5e'24", + "5.24", + "5e 2024", + "D&D 5e", + "DnD 5e", + "DnD5e", + "D&D 5e24", + "DnD5e24", + "D&D 2024", + "system:pf2e", + "system:dnd5.5", + "system:dnd5e", + "system:dnd", + "system:5e", + "system:d&d5e", + "system:D&D 5e24", + "system:book clone", + "system:curse of strahd", + "system:descent into avernus", + "system:GM Binder", + "system:Ord", + "system:sf2e", + "system:Mutants and Masterminds", + "system:2e", + "system:class", + "PF2e", + "pf2e", + "3.5e", + "3.5", + "system:pf2e", + "DnD", + "DND", + "dnd", + "dnd-2014", + "dnd-2024", + "dnd5e", + "DnD 5e", + "DnD5e24", + "DnDBeyond", + "DnDBehindTheScreen", + "Dd5", + "DD5", + "dd5", + "dd5e", + "system:D&D", + "system:D&D 5e24", + "system:d&d5e", + "system:5e", + "system:daggerheart", + "system:dnd5e", + "system:dnd5.5", + "system:dnd", + "system:GM Binder", + "system:Ord", + "system:sf2e", + "system:curse of strahd", + "system:descent into avernus", + "system:class", + "system:Mutants and Masterminds", + "system:2e", + + // Media / Pop Culture + "One Piece", + "One Piece DND", + "Luffy", + "Dragon Ball", + "Dragon Ball Z", + "Dragon Ball Z TTRPG", + "Dragon Ball Z RPG", + "Dragon Ball Z DND", + "Dragon Ball Z 5e", + "Naruto", + "Naruto 5e", + "Jujutsu Kaisen", + "Fairy Tail", + "Final Fantasy", + "Final Fantasy XIV", + "Final Fantasy 7 Remake", + "FF7", + "FFXI", + "Kingdom Hearts", + "Elder Scrolls", + "Elder Scrolls Offline", + "Skyrim", + "WoW", + "World of Warcraft", + "Marvel Comics", + "DC Comics", + "Pokémon", + "Pokemon", + "League of Legends", + "Runeterra", + "Yu-Gi-Oh", + "Minecraft", + "Minecraft Mods", + "Don't Starve", + "Witcher", + "Witcher 3", + "Cyberpunk", + "Cyberpunk 2077", + "Fallout", + "Divinity Original Sin 2", + "Fullmetal Alchemist", + "Fullmetal Alchemist Brotherhood", + "Lobotomy Corporation", + "Bloodborne", + "Dragonlance", + "Shackled City Adventure Path", + "Baldurs Gate 3", + "Library of Ruina", + "Radiant Citadel", + "Ravenloft", + "Forgotten Realms", + "Exandria", + "Critical Role", + "Star Wars", + "SW5e", + "SW5E", + "Star Wars 5e", + + // Tools / Resources / Templates / Notes + "Template", + "Templates", + "Style Template", + "meta:Template", + "meta:Theme", + "meta:5e24 Style", + "meta:khaoz age", + "meta:gratis", + "meta:free", + "meta:Sheet", + "meta:documentation", + "meta:npc", + "meta:User Guide", + "fa-solid fa-sheet-plastic:Ficha", + "tag:Class", + "tag:Rules", + "tag:Spells", + "tag:Adventure", + "tag:Spell List", + "tag:TAoF&F", + "tag:Berean", + "resource", + "Resources", + "support", + "user help", + "notes", + "note", + "quick ref", + "reminder cards", + "syntax", + "css", + "custom css", + "example", + "examples", + "snippet", + "snippets", + "tables", + "chart", + "stat block", + "stat blocks", + "statblock", +]; diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index eb5912f23..3a57d620d 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -2,7 +2,7 @@ import "./tagInput.less"; import React, { useState, useEffect, useMemo } from "react"; import Combobox from "../../../components/combobox.jsx"; -import tagSuggestionList from "./tagSuggestionList.js"; +import tagSuggestionList from "./curatedTagSuggestionList.js"; const TagInput = ({ label, unique = true, values = [], placeholder = "", onChange }) => { const [tagList, setTagList] = useState( @@ -81,16 +81,44 @@ const TagInput = ({ label, unique = true, values = [], placeholder = "", onChang setTagList((prev) => prev.map((t, i) => ({ ...t, editing: i === index }))); }; - const suggestionOptions = tagSuggestionList.map((tag) => ( -
      - {tag} -
      - )); + const suggestionOptions = tagSuggestionList.map((tag) => { + + const tagType = tag.split(':'); + + let classes = 'item'; + switch (tagType[0]) { + case 'type': + classes = 'item type' + break; + + case 'group': + classes = 'item group' + break; + + case 'meta': + classes = 'item meta' + break; + + case 'system': + classes = 'item system' + break; + + default: + classes = 'item' + break; + } + + return ( +
      + {tag} +
      + ); + }); return (
      diff --git a/client/homebrew/editor/tagInput/tagInput.less b/client/homebrew/editor/tagInput/tagInput.less index e69de29bb..392bd3edd 100644 --- a/client/homebrew/editor/tagInput/tagInput.less +++ b/client/homebrew/editor/tagInput/tagInput.less @@ -0,0 +1,18 @@ +.tagInput-dropdown { + .dropdown-options { + .item { + &.type { + background-color: #00800035; + } + &.group { + background-color: #50505035; + } + &.meta { + background-color: #00008035; + } + &.system { + background-color: #80000035; + } + } + } +} diff --git a/client/homebrew/editor/tagInput/tagSuggestionList.js b/client/homebrew/editor/tagInput/tagSuggestionList.js index df2dfb7dc..6b8e4060e 100644 --- a/client/homebrew/editor/tagInput/tagSuggestionList.js +++ b/client/homebrew/editor/tagInput/tagSuggestionList.js @@ -750,27 +750,6 @@ export default [ "Arvore I", "Fim da Jornada", "greek god", - "-1 OR 5*5=25 --", - "-1 OR 5*5=26 --", - "-1 OR 5*5=25", - "-1 OR 5*5=26", - "-1' OR 5*5=25 --", - "-1' OR 5*5=26 --", - "-1\" OR 5*5=25 --", - "-1\" OR 5*5=26 --", - "1*if(now()=sysdate(),sleep(15),0)", - "10'XOR(1*if(now()=sysdate(),sleep(15),0))XOR'Z", - "10\"XOR(1*if(now()=sysdate(),sleep(15),0))XOR\"Z", - "(select(0)from(select(sleep(15)))v)/*'+(select(0)from(select(sleep(15)))v)+'\"+(select(0)from(select(sleep(15)))v)+\"*/", - "1-1; waitfor delay '0:0:15' --", - "1-1); waitfor delay '0:0:15' --", - "1-1 waitfor delay '0:0:15' --", - "1*DBMS_PIPE.RECEIVE_MESSAGE(CHR(99)||CHR(99)||CHR(99),15)", - "1'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(98),15)||'", - "'\"", - "����%2527%2522\\'\\\"", - "(select 198766*667891)", - "(select 198766*667891 from DUAL)", "dwarf", "Firearms", "3.5e", @@ -1347,7 +1326,6 @@ export default [ "system:sf2e", "drakkenheim", "downtime", - "v1.1", "amulet", "Feiticeiros e Maldicoes", "Tecnica amaldicoada", From 694f5dcd211700d0f0cfb62fd1719c008be22b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Sun, 15 Feb 2026 23:54:24 +0100 Subject: [PATCH 04/11] fix auth input --- client/homebrew/editor/tagInput/tagInput.jsx | 52 ++++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 3a57d620d..cbe7c723f 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -12,7 +12,7 @@ const TagInput = ({ label, unique = true, values = [], placeholder = "", onChang editing: false, })), ); - + //console.log(label, values, placeholder); // Keep in sync if parent updates values useEffect(() => { const incoming = values || []; @@ -82,29 +82,28 @@ const TagInput = ({ label, unique = true, values = [], placeholder = "", onChang }; const suggestionOptions = tagSuggestionList.map((tag) => { + const tagType = tag.split(":"); - const tagType = tag.split(':'); - - let classes = 'item'; + let classes = "item"; switch (tagType[0]) { - case 'type': - classes = 'item type' + case "type": + classes = "item type"; break; - case 'group': - classes = 'item group' + case "group": + classes = "item group"; break; - case 'meta': - classes = 'item meta' + case "meta": + classes = "item meta"; break; - - case 'system': - classes = 'item system' + + case "system": + classes = "item system"; break; - + default: - classes = 'item' + classes = "item"; break; } @@ -168,20 +167,21 @@ const TagInput = ({ label, unique = true, values = [], placeholder = "", onChang className="tagInput-dropdown" default="" placeholder={placeholder} - options={suggestionOptions} - autoSuggest={{ - suggestMethod: "startsWith", - clearAutoSuggestOnClick: true, - filterOn: ["value", "title"], - }} - onSelect={(value) => { - submitTag(value, null); - }} + options={label === "tags" ? suggestionOptions : []} // always array + autoSuggest={ + label === "tags" + ? { + suggestMethod: "startsWith", + clearAutoSuggestOnClick: true, + filterOn: ["value", "title"], + } + : { suggestMethod: "includes", clearAutoSuggestOnClick: true, filterOn: [] } // empty filter + } + onSelect={(value) => submitTag(value)} onEntry={(e) => { - // Allow free typing + Enter if (e.key === "Enter") { e.preventDefault(); - submitTag(e.target.value, null); + submitTag(e.target.value); } }} /> From 2a9970705b88933b0081e80d6e5405c6f2cecc24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 16 Feb 2026 00:17:39 +0100 Subject: [PATCH 05/11] fix regex and fixed substrings --- client/homebrew/editor/tagInput/tagInput.jsx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index cbe7c723f..f44264a9e 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -13,7 +13,7 @@ const TagInput = ({ label, unique = true, values = [], placeholder = "", onChang })), ); //console.log(label, values, placeholder); - // Keep in sync if parent updates values + useEffect(() => { const incoming = values || []; const current = tagList.map((t) => t.value); @@ -31,25 +31,34 @@ const TagInput = ({ label, unique = true, values = [], placeholder = "", onChang } }, [values]); - // Emit changes upward useEffect(() => { onChange?.({ target: { value: tagList.map((t) => t.value) }, }); }, [tagList]); - // Canonical duplicate groups const duplicateGroups = [ + ["5e 2024", "5.5e", "5e'24", "5.24", "5e24", "5.5"], + ["5e", "5th Edition"], + ["Dungeons & Dragons", "Dungeons and Dragons", "Dungeons n dragons"], ["D&D", "DnD", "dnd", "Dnd", "dnD", "d&d", "d&D", "D&d"], ["P2e", "p2e", "P2E", "Pathfinder 2e"], + ["meta:", "Meta:", "META:"], + ["group:", "Group:", "GROUP:"], + ["type:", "Type:", "TYPE:"], + ["system:", "System:", "SYSTEM:"], ]; const normalizeValue = (input) => { - const group = duplicateGroups.find((grp) => grp.some((tag) => tag.toLowerCase() === input.toLowerCase())); + const lowerInput = input.toLowerCase(); + const group = duplicateGroups.find((grp) => grp.some((tag) => tag && lowerInput.includes(tag.toLowerCase()))); return group ? group[0] : input; }; - const regexPattern = /^[-A-Za-z0-9&_.()]+$/; + const regexPattern = + label === "tags" + ? /^[-A-Za-z0-9&_.()]+$/ // only allowed chars for tags + : /^.*$/; // allow all characters otherwise const submitTag = (newValue, index = null) => { const trimmed = newValue?.trim(); From dec91cc76ef78321b5a9a8740f03f917f691ce07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 16 Feb 2026 00:58:50 +0100 Subject: [PATCH 06/11] next stable --- client/components/combobox.jsx | 8 ++++ .../editor/metadataEditor/metadataEditor.jsx | 37 ++----------------- .../editor/metadataEditor/metadataEditor.less | 2 +- client/homebrew/editor/tagInput/tagInput.jsx | 37 +++++++++++-------- 4 files changed, 33 insertions(+), 51 deletions(-) diff --git a/client/components/combobox.jsx b/client/components/combobox.jsx index 651a31516..b80bccd1c 100644 --- a/client/components/combobox.jsx +++ b/client/components/combobox.jsx @@ -16,6 +16,7 @@ const Combobox = createReactClass({ suggestMethod : 'includes', filterOn : [] // should allow as array to filter on multiple attributes, or even custom filter }, + valuePatterns: [/.+/] }; }, getInitialState : function() { @@ -74,6 +75,7 @@ const Combobox = createReactClass({ type='text' onChange={(e)=>this.handleInput(e)} value={this.state.value || ''} + pattern={this.props.valuePatterns} placeholder={this.props.placeholder} onBlur={(e)=>{ if(!e.target.checkValidity()){ @@ -82,6 +84,12 @@ const Combobox = createReactClass({ }); } }} + onKeyDown={(e)=>{ + if (e.key === "Enter") { + e.preventDefault(); + this.props.onEntry(e); + } + }} />
      diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 0b538f2b5..1d78eef60 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -10,8 +10,6 @@ import TagInput from '../tagInput/tagInput.jsx'; import Themes from 'themes/themes.json'; import validations from './validations.js'; -const SYSTEMS = ['5e', '4e', '3.5e', 'Pathfinder']; - import homebreweryThumbnail from '../../thumbnail.png'; const callIfExists = (val, fn, ...args)=>{ @@ -33,7 +31,6 @@ const MetadataEditor = createReactClass({ tags : [], published : false, authors : [], - systems : [], renderer : 'legacy', theme : '5ePHB', lang : 'en' @@ -91,15 +88,6 @@ const MetadataEditor = createReactClass({ } }, - handleSystem : function(system, e){ - if(e.target.checked){ - this.props.metadata.systems.push(system); - } else { - this.props.metadata.systems = _.without(this.props.metadata.systems, system); - } - this.props.onChange(this.props.metadata); - }, - handleRenderer : function(renderer, e){ if(e.target.checked){ this.props.metadata.renderer = renderer; @@ -155,18 +143,6 @@ const MetadataEditor = createReactClass({ }); }, - renderSystems : function(){ - return _.map(SYSTEMS, (val)=>{ - return ; - }); - }, - renderPublish : function(){ if(this.props.metadata.published){ return
    - !this.props.metadata.authors?.includes(v)]} placeholder='invite author' unique={true} diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index f272a605c..9f7f71498 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -1,126 +1,130 @@ -import "./tagInput.less"; -import React, { useState, useEffect, useMemo } from "react"; -import Combobox from "../../../components/combobox.jsx"; +import './tagInput.less'; +import React, { useState, useEffect } from 'react'; +import Combobox from '../../../components/combobox.jsx'; -import tagSuggestionList from "./curatedTagSuggestionList.js"; +import tagSuggestionList from './curatedTagSuggestionList.js'; -const TagInput = ({ label, valuePatterns, values = [], unique = true, placeholder = "", smallText = "", onChange }) => { +const TagInput = ({ label, valuePatterns, values = [], unique = true, placeholder = '', smallText = '', onChange })=>{ const [tagList, setTagList] = useState( - values.map((value) => ({ + values.map((value)=>({ value, - display: value.trim(), - editing: false, + editing : false, + draft : '', })), ); - useEffect(() => { + useEffect(()=>{ const incoming = values || []; - const current = tagList.map((t) => t.value); + const current = tagList.map((t)=>t.value); - const changed = incoming.length !== current.length || incoming.some((v, i) => v !== current[i]); + const changed = incoming.length !== current.length || incoming.some((v, i)=>v !== current[i]); - if (changed) { + if(changed) { setTagList( - incoming.map((value) => ({ + incoming.map((value)=>({ value, - display: value.trim(), - editing: false, + editing : false, })), ); } }, [values]); - useEffect(() => { + useEffect(()=>{ onChange?.({ - target: { value: tagList.map((t) => t.value) }, + target : { value: tagList.map((t)=>t.value) }, }); }, [tagList]); + // substrings to be normalized to the first value on the array const duplicateGroups = [ - ["5e 2024", "5.5e", "5e'24", "5.24", "5e24", "5.5"], - ["5e", "5th Edition"], - ["Dungeons & Dragons", "Dungeons and Dragons", "Dungeons n dragons"], - ["D&D", "DnD", "dnd", "Dnd", "dnD", "d&d", "d&D", "D&d"], - ["P2e", "p2e", "P2E", "Pathfinder 2e"], - ["meta:", "Meta:", "META:"], - ["group:", "Group:", "GROUP:"], - ["type:", "Type:", "TYPE:"], - ["system:", "System:", "SYSTEM:"], + ['5e 2024', '5.5e', '5e\'24', '5.24', '5e24', '5.5'], + ['5e', '5th Edition'], + ['Dungeons & Dragons', 'Dungeons and Dragons', 'Dungeons n dragons'], + ['D&D', 'DnD', 'dnd', 'Dnd', 'dnD', 'd&d', 'd&D', 'D&d'], + ['P2e', 'p2e', 'P2E', 'Pathfinder 2e'], ]; - const normalizeValue = (input) => { + const normalizeValue = (input)=>{ const lowerInput = input.toLowerCase(); + let normalizedTag = input; for (const group of duplicateGroups) { for (const tag of group) { - if (!tag) continue; + if(!tag) continue; const index = lowerInput.indexOf(tag.toLowerCase()); - if (index !== -1) { - return input.slice(0, index) + group[0] + input.slice(index + tag.length); + if(index !== -1) { + normalizedTag = input.slice(0, index) + group[0] + input.slice(index + tag.length); + break; } } } - return input; + if(normalizedTag.includes(':')) { + const [rawType, rawValue = ''] = normalizedTag.split(':'); + const tagType = rawType.trim().toLowerCase(); + const tagValue = rawValue.trim(); + + if(tagValue.length > 0) { + normalizedTag = `${tagType}:${tagValue[0].toUpperCase()}${tagValue.slice(1)}`; + } + //trims spaces around colon and capitalizes the first word after the colon + //this is preferred to users not understanding they can't put spaces in + } + + return normalizedTag; }; - const submitTag = (newValue, index = null) => { + const submitTag = (newValue, index = null)=>{ const trimmed = newValue?.trim(); - console.log(newValue, trimmed); - if (!trimmed) return; - console.log(valuePatterns.test(trimmed)); - if (!valuePatterns.test(trimmed)) return; + if(!trimmed) return; + if(!valuePatterns.test(trimmed)) return; - const canonical = normalizeValue(trimmed); + const normalizedTag = normalizeValue(trimmed); - setTagList((prev) => { - const existsIndex = prev.findIndex((t) => t.value.toLowerCase() === canonical.toLowerCase()); - - if (unique && existsIndex !== -1) return prev; - - if (index !== null) { - return prev.map((t, i) => - i === index ? { ...t, value: canonical, display: canonical, editing: false } : t, - ); + setTagList((prev)=>{ + const existsIndex = prev.findIndex((t)=>t.value.toLowerCase() === normalizedTag.toLowerCase()); + if(unique && existsIndex !== -1) return prev; + if(index !== null) { + return prev.map((t, i)=>(i === index ? { ...t, value: normalizedTag, editing: false } : t)); } - return [...prev, { value: canonical, display: canonical, editing: false }]; + return [...prev, { value: normalizedTag, editing: false }]; }); }; - const removeTag = (index) => { - setTagList((prev) => prev.filter((_, i) => i !== index)); + const removeTag = (index)=>{ + setTagList((prev)=>prev.filter((_, i)=>i !== index)); }; - const editTag = (index) => { - setTagList((prev) => prev.map((t, i) => ({ ...t, editing: i === index }))); + const editTag = (index)=>{ + setTagList((prev)=>prev.map((t, i)=>(i === index ? { ...t, editing: true, draft: t.value } : t))); }; - const suggestionOptions = tagSuggestionList.map((tag) => { - const tagType = tag.split(":"); + const stopEditing = (index)=>{ + setTagList((prev)=>prev.map((t, i)=>(i === index ? { ...t, editing: false, draft: '' } : t))); + }; - let classes = "item"; + const suggestionOptions = tagSuggestionList.map((tag)=>{ + const tagType = tag.split(':'); + + let classes = 'item'; switch (tagType[0]) { - case "type": - classes = "item type"; - break; - - case "group": - classes = "item group"; - break; - - case "meta": - classes = "item meta"; - break; - - case "system": - classes = "item system"; - break; - - default: - classes = "item"; - break; + case 'type': + classes = 'item type'; + break; + case 'group': + classes = 'item group'; + break; + case 'meta': + classes = 'item meta'; + break; + case 'system': + classes = 'item system'; + break; + default: + classes = 'item'; + break; } return ( @@ -131,68 +135,70 @@ const TagInput = ({ label, valuePatterns, values = [], unique = true, placeholde }); return ( -
    +
    {label && } -
    -
      - {tagList.map((t, i) => - t.editing ? ( - { - const val = e.target.value; - setTagList((prev) => - prev.map((tag, idx) => (idx === i ? { ...tag, display: val } : tag)), +
      +
        + {tagList.map((t, i)=>t.editing ? ( + setTagList((prev)=>prev.map((tag, idx)=>(idx === i ? { ...tag, draft: e.target.value } : tag)), + ) + } + onKeyDown={(e)=>{ + if(e.key === 'Enter') { + e.preventDefault(); + submitTag(t.draft, i); // submit draft + setTagList((prev)=>prev.map((tag, idx)=>(idx === i ? { ...tag, draft: '' } : tag)), ); - }} - onKeyDown={(e) => { - if (e.key === "Enter") { - e.preventDefault(); - submitTag(e.target.value, i); - } - }} - autoFocus - /> - ) : ( -
      • editTag(i)}> - {t.display} - -
      • - ), + } + if(e.key === 'Escape') { + stopEditing(i); + e.target.blur(); + } + }} + autoFocus + /> + ) : ( +
      • editTag(i)}> + {t.value} + +
      • + ), )}
      submitTag(value)} - onEntry={(e) => { - if (e.key === "Enter") { - console.log("submit"); + onSelect={(value)=>submitTag(value)} + onEntry={(e)=>{ + if(e.key === 'Enter') { + console.log('submit'); e.preventDefault(); submitTag(e.target.value); } diff --git a/client/homebrew/editor/tagInput/tagInput.less b/client/homebrew/editor/tagInput/tagInput.less index 392bd3edd..3165b3935 100644 --- a/client/homebrew/editor/tagInput/tagInput.less +++ b/client/homebrew/editor/tagInput/tagInput.less @@ -1,16 +1,20 @@ +.list input { + border-radius: 5px; +} + .tagInput-dropdown { .dropdown-options { .item { &.type { background-color: #00800035; } - &.group { + &.group { background-color: #50505035; } - &.meta { + &.meta { background-color: #00008035; } - &.system { + &.system { background-color: #80000035; } } From 5171d1154ed2ce3b9609be753ef62dd23d31d343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Tue, 17 Feb 2026 14:47:20 +0100 Subject: [PATCH 09/11] normalize caps --- .../tagInput/curatedTagSuggestionList.js | 69 +++++++++---------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/client/homebrew/editor/tagInput/curatedTagSuggestionList.js b/client/homebrew/editor/tagInput/curatedTagSuggestionList.js index c20dec445..d433175ef 100644 --- a/client/homebrew/editor/tagInput/curatedTagSuggestionList.js +++ b/client/homebrew/editor/tagInput/curatedTagSuggestionList.js @@ -29,9 +29,9 @@ export default [ "system:Draw Steel", "system:Mutants and Masterminds", - // ###################################### RPG Keywords - // Meta + "meta:V3", + "meta:Legacy", "meta:Template", "meta:Theme", "meta:free", @@ -39,12 +39,31 @@ export default [ "meta:Documentation", "meta:NPC", "meta:Guide", - "Resource", - "notes", - "syntax", - "example", - "stat block", - "Character Sheet", + "meta:Resource", + "meta:Notes", + "meta:Example", + + // Book type + "type:Campaign", + "type:Campaign Setting", + "type:Adventure", + "type:One-Shot", + "type:Setting", + "type:World", + "type:Lore", + "type:History", + "type:Dungeon Master", + "type:Encounter Pack", + "type:Encounter", + "type:Session Notes", + "type:reference", + "type:Handbook", + "type:Manual", + "type:Manuals", + "type:Compendium", + "type:Bestiary", + + // ###################################### RPG Keywords // Classes / Subclasses / Archetypes "Class", @@ -96,16 +115,15 @@ export default [ "Artifact", "Spell", "Spells", - "cantrip", - "cantrips", + "Cantrip", + "Cantrips", "Eldritch", "Eldritch Invocation", - "invocation", + "Invocation", "Invocations", - "pact boon", + "Pact boon", "Pact Boon", "Spellcaster", - "spellcaster", "Spellblade", "Magical Tattoos", "Enchantment", @@ -123,26 +141,6 @@ export default [ "Items", "Bag of Holding", - // Book type - "type:Campaign", - "type:Campaign Setting", - "type:Adventure", - "type:One-Shot", - "type:Setting", - "type:World", - "type:Lore", - "type:History", - "type:Dungeon Master", - "type:Encounter Pack", - "type:Encounter", - "type:Session Notes", - "type:reference", - "type:Handbook", - "type:Manual", - "type:Manuals", - "type:Compendium", - "type:Bestiary", - // Monsters / Creatures / Enemies "Monster", "Creatures", @@ -165,11 +163,6 @@ export default [ "Boss", "BBEG", - // ############################# Document meta tags - - "meta:v3", - "meta:Legacy", - // ############################# Media / Pop Culture "One Piece", "Dragon Ball", From 20b8a5b0b1d61c68e411ba7613a06c7c99171db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Tue, 17 Feb 2026 14:49:38 +0100 Subject: [PATCH 10/11] both \ and / as valid chars --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 9082633e5..721340079 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -341,7 +341,7 @@ const MetadataEditor = createReactClass({ Date: Tue, 17 Feb 2026 15:03:05 +0100 Subject: [PATCH 11/11] npm sync --- package-lock.json | 511 +++++++++++++++++++++++++++++----------------- 1 file changed, 321 insertions(+), 190 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0ce729dff..db6143f52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -94,23 +94,120 @@ "license": "MIT" }, "node_modules/@asamuzakjp/css-color": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz", - "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.2.tgz", + "integrity": "sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==", "dev": true, "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.2.4" + "@csstools/css-calc": "^3.0.0", + "@csstools/css-color-parser": "^4.0.1", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.2.5" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-calc": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz", + "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-color-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.1.tgz", + "integrity": "sha512-vYwO15eRBEkeF6xjAno/KQ61HacNhfQuuU/eGwH67DplL0zD5ZixUa563phQvUelA07yDczIXdtmYojCphKJcw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.0.1", + "@csstools/css-calc": "^3.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.19.0" } }, "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", - "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -118,9 +215,9 @@ } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "6.7.7", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.7.tgz", - "integrity": "sha512-8CO/UQ4tzDd7ula+/CVimJIVWez99UJlbMyIgk8xOnhAVPKLnBZmUFYVgugS441v2ZqUq5EnSh6B0Ua0liSFAA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -128,13 +225,13 @@ "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.5" + "lru-cache": "^11.2.6" } }, "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", - "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -176,6 +273,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -202,9 +300,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", @@ -1853,6 +1951,7 @@ "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", @@ -1929,6 +2028,19 @@ "dev": true, "license": "MIT" }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, "node_modules/@cacheable/memory": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.0.7.tgz", @@ -1965,19 +2077,20 @@ "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@keyv/serialize": "^1.1.1" } }, "node_modules/@cacheable/utils": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.3.3.tgz", - "integrity": "sha512-JsXDL70gQ+1Vc2W/KUFfkAJzgb4puKwwKehNLuB+HrNKWf91O736kGfxn4KujXCCSuh6mRRL4XEB0PkAFjWS0A==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.3.4.tgz", + "integrity": "sha512-knwKUJEYgIfwShABS1BX6JyJJTglAFcEU7EXqzTdiGCXur4voqkiJkdgZIQtWNFhynzDWERcTYv/sETMu3uJWA==", "dev": true, "license": "MIT", "dependencies": { "hashery": "^1.3.0", - "keyv": "^5.5.5" + "keyv": "^5.6.0" } }, "node_modules/@cacheable/utils/node_modules/keyv": { @@ -1991,9 +2104,9 @@ } }, "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.1.tgz", + "integrity": "sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ==", "dev": true, "funding": [ { @@ -2007,59 +2120,7 @@ ], "license": "MIT-0", "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "node": ">=20.19.0" } }, "node_modules/@csstools/css-parser-algorithms": { @@ -2078,6 +2139,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -2086,9 +2148,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.26", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.26.tgz", - "integrity": "sha512-6boXK0KkzT5u5xOgF6TKB+CLq9SOpEGmkZw0g5n9/7yg85wab3UzSxB8TxhLJ31L4SGJ6BCFRw/iftTha1CJXA==", + "version": "1.0.27", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.27.tgz", + "integrity": "sha512-sxP33Jwg1bviSUXAV43cVYdmjt2TLnLXNqCWl9xmxHawWVjGz/kEbdkr7F9pxJNBN2Mh+dq0crgItbW6tQvyow==", "dev": true, "funding": [ { @@ -2118,6 +2180,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -2378,9 +2441,9 @@ } }, "node_modules/@exodus/bytes": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.11.0.tgz", - "integrity": "sha512-wO3vd8nsEHdumsXrjGO/v4p6irbg7hy9kvIeR6i2AwylZSk4HJdWgL0FNaVquW1+AweJcdvU1IEpuIWk/WaPnA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.14.1.tgz", + "integrity": "sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==", "dev": true, "license": "MIT", "engines": { @@ -2922,9 +2985,9 @@ "license": "MIT" }, "node_modules/@mongodb-js/saslprep": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.5.tgz", - "integrity": "sha512-k64Lbyb7ycCSXHSLzxVdb2xsKGPMvYZfCICXvDsI8Z65CeWQzTEKS4YmGbnqw+U9RBvLPTsB6UCmwkgsDTGWIw==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.6.tgz", + "integrity": "sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g==", "license": "MIT", "dependencies": { "sparse-bitfield": "^3.0.3" @@ -2948,6 +3011,7 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", + "peer": true, "engines": { "node": "^14.21.3 || >=16" }, @@ -3181,9 +3245,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", - "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3230,14 +3294,14 @@ "license": "MIT" }, "node_modules/@typescript-eslint/project-service": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", - "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", + "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.54.0", - "@typescript-eslint/types": "^8.54.0", + "@typescript-eslint/tsconfig-utils": "^8.56.0", + "@typescript-eslint/types": "^8.56.0", "debug": "^4.4.3" }, "engines": { @@ -3252,14 +3316,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", - "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", + "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0" + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3270,9 +3334,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", - "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", + "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", "dev": true, "license": "MIT", "engines": { @@ -3287,9 +3351,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", "dev": true, "license": "MIT", "engines": { @@ -3301,16 +3365,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", - "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", + "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.54.0", - "@typescript-eslint/tsconfig-utils": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/project-service": "8.56.0", + "@typescript-eslint/tsconfig-utils": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", @@ -3355,9 +3419,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -3368,16 +3432,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", - "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", + "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0" + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3387,19 +3451,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", - "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", + "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.54.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.56.0", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3409,6 +3473,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -3704,6 +3781,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4710,6 +4788,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -4904,9 +4983,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001767", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz", - "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==", + "version": "1.0.30001770", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz", + "integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==", "funding": [ { "type": "opencollective", @@ -5134,9 +5213,9 @@ } }, "node_modules/codemirror": { - "version": "5.65.20", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.20.tgz", - "integrity": "sha512-i5dLDDxwkFCbhjvL2pNjShsojoL3XHyDwsGv1jqETUoW+lzpBKKqNTUWgQwVAOa0tUm4BwekT455ujafi8payA==", + "version": "5.65.21", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.21.tgz", + "integrity": "sha512-6teYk0bA0nR3QP0ihGMoxuKzpl5W80FpnHpBJpgy66NK3cZv5b/d/HY8PnRvfSsCG1MTfr92u2WUl+wT0E40mQ==", "license": "MIT" }, "node_modules/collect-v8-coverage": { @@ -5515,13 +5594,13 @@ } }, "node_modules/css-functions-list": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz", - "integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.3.3.tgz", + "integrity": "sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==", "dev": true, "license": "MIT", "engines": { - "node": ">=12 || >=16" + "node": ">=12" } }, "node_modules/css-tree": { @@ -5552,25 +5631,25 @@ } }, "node_modules/cssstyle": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.7.tgz", - "integrity": "sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.0.1.tgz", + "integrity": "sha512-IoJs7La+oFp/AB033wBStxNOJt4+9hHMxsXUPANcoXL2b3W4DZKghlJ2cI/eyeRZIQ9ysvYEorVhjrcYctWbog==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^4.1.1", - "@csstools/css-syntax-patches-for-csstree": "^1.0.21", + "@asamuzakjp/css-color": "^4.1.2", + "@csstools/css-syntax-patches-for-csstree": "^1.0.26", "css-tree": "^3.1.0", - "lru-cache": "^11.2.4" + "lru-cache": "^11.2.5" }, "engines": { "node": ">=20" } }, "node_modules/cssstyle/node_modules/lru-cache": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", - "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -6274,6 +6353,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -6329,9 +6409,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "29.12.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.12.2.tgz", - "integrity": "sha512-IIRg0IZ5yuERfzOZrKuNScxk9yeuKo0M4Urx7RZcthK5HE/8gJUY518bdi7picLRBJVctjOW3yVx0zyBp4Cq+g==", + "version": "29.15.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.0.tgz", + "integrity": "sha512-ZCGr7vTH2WSo2hrK5oM2RULFmMruQ7W3cX7YfwoTiPfzTGTFBMmrVIz45jZHd++cGKj/kWf02li/RhTGcANJSA==", "dev": true, "license": "MIT", "dependencies": { @@ -6342,7 +6422,7 @@ }, "peerDependencies": { "@typescript-eslint/eslint-plugin": "^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "jest": "*", "typescript": ">=4.8.4 <6.0.0" }, @@ -6392,19 +6472,25 @@ } }, "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "version": "2.0.0-next.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", + "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8777,9 +8863,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -8872,6 +8958,7 @@ "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "30.2.0", "@jest/types": "30.2.0", @@ -9352,9 +9439,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -9498,16 +9585,18 @@ } }, "node_modules/jsdom": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.0.0.tgz", - "integrity": "sha512-KDYJgZ6T2TKdU8yBfYueq5EPG/EylMsBvCaenWMJb2OXmjgczzwveRCoJ+Hgj1lXPDyasvrgneSn4GBuR1hYyA==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.1.0.tgz", + "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@acemir/cssom": "^0.9.31", - "@asamuzakjp/dom-selector": "^6.7.6", + "@asamuzakjp/dom-selector": "^6.8.1", + "@bramus/specificity": "^2.4.2", "@exodus/bytes": "^1.11.0", - "cssstyle": "^5.3.7", + "cssstyle": "^6.0.1", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", @@ -9518,7 +9607,7 @@ "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.0", - "undici": "^7.20.0", + "undici": "^7.21.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", @@ -9947,9 +10036,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -9995,6 +10084,7 @@ "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", "license": "MIT", + "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -10490,6 +10580,22 @@ "url": "https://opencollective.com/mongoose" } }, + "node_modules/mongoose/node_modules/gcp-metadata": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz", + "integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/mongoose/node_modules/mongodb": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.0.0.tgz", @@ -10840,6 +10946,25 @@ "node": ">=10.5.0" } }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/node-fetch": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", @@ -11566,6 +11691,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -11628,6 +11754,7 @@ "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -11642,7 +11769,6 @@ "integrity": "sha512-Mn8KJ45HNNG6JBpBizXcyf6LqY/qyqetGcou/nprDnFwBFBLGj0j/sNKV2lj2KMOVOwdXu14aEzqJv8CIV6e8g==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "postcss": "^8.4.20" } @@ -11731,6 +11857,7 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -11920,6 +12047,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -11932,6 +12060,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -13534,6 +13663,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-syntax-patches-for-csstree": "^1.0.19", @@ -13583,9 +13713,9 @@ } }, "node_modules/stylelint-config-recess-order": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recess-order/-/stylelint-config-recess-order-7.6.0.tgz", - "integrity": "sha512-c3LXX4a8UEtrMD/KigK4I7LFexbM2p/eSTqnix5dmmvydEqX3dzrRt981h8giSEhA51vxdCEefQc3umH60i2bA==", + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/stylelint-config-recess-order/-/stylelint-config-recess-order-7.6.1.tgz", + "integrity": "sha512-ac0H/Iy2chh1YBADrua87G+nJCmG/SdG7gjnoLvtfpN0D+RuNfuADawfbCKvm0LMp5hvuRFNkJsu6xNoLM5ToA==", "dev": true, "license": "ISC", "peerDependencies": { @@ -13882,9 +14012,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { @@ -14055,6 +14185,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -14063,22 +14194,22 @@ } }, "node_modules/tldts": { - "version": "7.0.21", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.21.tgz", - "integrity": "sha512-Plu6V8fF/XU6d2k8jPtlQf5F4Xx2hAin4r2C2ca7wR8NK5MbRTo9huLUWRe28f3Uk8bYZfg74tit/dSjc18xnw==", + "version": "7.0.23", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.23.tgz", + "integrity": "sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.0.21" + "tldts-core": "^7.0.23" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.21", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.21.tgz", - "integrity": "sha512-oVOMdHvgjqyzUZH1rOESgJP1uNe2bVrfK0jUHHmiM2rpEiRbf3j4BrsIc6JigJRbHGanQwuZv/R+LTcHsw+bLA==", + "version": "7.0.23", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.23.tgz", + "integrity": "sha512-0g9vrtDQLrNIiCj22HSe9d4mLVG3g5ph5DZ8zCKBr4OtrspmNB6ss7hVyzArAeE88ceZocIEGkyW1Ime7fxPtQ==", "dev": true, "license": "MIT" }, @@ -14495,9 +14626,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.20.0.tgz", - "integrity": "sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ==", + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", + "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", "dev": true, "license": "MIT", "engines": {