autumnnote 1.16.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -2
- package/dist/autumnnote.cjs +20 -20
- package/dist/autumnnote.css +1 -1
- package/dist/autumnnote.es.js +1521 -6319
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.min.js +20 -20
- package/dist/autumnnote.umd.js +20 -20
- package/dist/autumnnote.umd.js.map +1 -1
- package/dist/emoji-data-BDQX5kh-.js +2331 -0
- package/dist/emoji-data-BDQX5kh-.js.map +1 -0
- package/package.json +6 -2
- package/src/js/Context.js +68 -8
- package/src/js/core/env.js +23 -10
- package/src/js/core/sanitise.js +81 -8
- package/src/js/i18n/all.js +27 -0
- package/src/js/i18n/index.js +45 -19
- package/src/js/index.js +12 -2
- package/src/js/index.umd.js +5 -0
- package/src/js/module/BaseMediaTooltip.js +142 -0
- package/src/js/module/BaseResizer.js +322 -0
- package/src/js/module/EmojiDialog.js +41 -494
- package/src/js/module/ImageResizer.js +23 -241
- package/src/js/module/ImageTooltip.js +16 -111
- package/src/js/module/TableTooltip.js +91 -220
- package/src/js/module/Toolbar.js +107 -2
- package/src/js/module/VideoResizer.js +38 -239
- package/src/js/module/VideoTooltip.js +27 -114
- package/src/js/module/emoji-data.js +496 -0
- package/src/js/module/table-grid.js +102 -0
- package/src/js/module/table-icons.js +33 -0
- package/src/styles/autumnnote.scss +11 -0
- package/types/i18n/all.d.ts +14 -0
- package/types/i18n/de.d.ts +4 -0
- package/types/i18n/en.d.ts +4 -0
- package/types/i18n/es.d.ts +4 -0
- package/types/i18n/fr.d.ts +4 -0
- package/types/i18n/ja.d.ts +4 -0
- package/types/i18n/ko.d.ts +4 -0
- package/types/i18n/vi.d.ts +4 -0
- package/types/i18n/zh.d.ts +4 -0
- package/types/index.d.ts +30 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emoji-data-BDQX5kh-.js","names":[],"sources":["../src/js/module/emoji-data.js"],"sourcesContent":["/**\n * emoji-data.js — Emoji catalogue for EmojiDialog.\n *\n * Kept in its own module and pulled in with a dynamic import so the ~25 KB\n * table (≈6 KB gzip) becomes a separate chunk instead of riding along in the\n * main bundle for every consumer, including those whose toolbar has no emoji\n * button. The UMD/CDN build inlines it again, since script tags cannot fetch\n * chunks.\n */\n\nexport const EMOJI_CATS = [\n { id: 'smileys', label: 'Smileys' },\n { id: 'people', label: 'People' },\n { id: 'animals', label: 'Animals' },\n { id: 'food', label: 'Food' },\n { id: 'travel', label: 'Travel' },\n { id: 'objects', label: 'Objects' },\n { id: 'symbols', label: 'Symbols' },\n];\n\n// [emoji_char, search_keywords, category]\nexport const EMOJI_LIST = [\n // Smileys & Emotions\n ['😀', 'grin smile happy face', 'smileys'],\n ['😃', 'happy smile big eyes', 'smileys'],\n ['😄', 'grinning smile laugh', 'smileys'],\n ['😁', 'beaming smile grin', 'smileys'],\n ['😆', 'laughing lol', 'smileys'],\n ['😅', 'sweat grin awkward', 'smileys'],\n ['🤣', 'rolling laugh rofl', 'smileys'],\n ['😂', 'tears laugh cry joy', 'smileys'],\n ['🙂', 'slight smile', 'smileys'],\n ['🙃', 'upside down smile', 'smileys'],\n ['😉', 'wink', 'smileys'],\n ['😊', 'blush smile happy', 'smileys'],\n ['😇', 'innocent halo angel', 'smileys'],\n ['🥰', 'hearts love adore', 'smileys'],\n ['😍', 'heart eyes love', 'smileys'],\n ['🤩', 'star eyes excited wow', 'smileys'],\n ['😘', 'kiss blow love', 'smileys'],\n ['😋', 'yum delicious tongue', 'smileys'],\n ['😛', 'tongue stuck out', 'smileys'],\n ['😜', 'wink tongue crazy', 'smileys'],\n ['🤪', 'zany crazy wild', 'smileys'],\n ['😝', 'squint tongue', 'smileys'],\n ['🤑', 'money mouth', 'smileys'],\n ['🤗', 'hugging hug', 'smileys'],\n ['🤔', 'thinking hmm', 'smileys'],\n ['🤨', 'raised eyebrow', 'smileys'],\n ['😐', 'neutral face', 'smileys'],\n ['😶', 'no mouth', 'smileys'],\n ['😏', 'smirk', 'smileys'],\n ['😒', 'unamused', 'smileys'],\n ['🙄', 'roll eyes', 'smileys'],\n ['😬', 'grimace', 'smileys'],\n ['😔', 'pensive sad', 'smileys'],\n ['😪', 'sleepy tired', 'smileys'],\n ['😴', 'sleeping zzz', 'smileys'],\n ['🤤', 'drool', 'smileys'],\n ['😷', 'mask sick', 'smileys'],\n ['🤒', 'sick thermometer', 'smileys'],\n ['🤕', 'hurt bandage', 'smileys'],\n ['🤢', 'nausea sick', 'smileys'],\n ['🤮', 'vomit sick', 'smileys'],\n ['🤧', 'sneeze cold', 'smileys'],\n ['🥵', 'hot sweat', 'smileys'],\n ['🥶', 'cold freeze', 'smileys'],\n ['😵', 'dizzy dead', 'smileys'],\n ['🤯', 'mind blown', 'smileys'],\n ['🤠', 'cowboy hat', 'smileys'],\n ['🥳', 'party celebrate', 'smileys'],\n ['😎', 'cool sunglasses', 'smileys'],\n ['🤓', 'nerd glasses', 'smileys'],\n ['🧐', 'monocle curious', 'smileys'],\n ['😕', 'confused', 'smileys'],\n ['😟', 'worried', 'smileys'],\n ['🙁', 'frown sad', 'smileys'],\n ['☹️', 'sad frown', 'smileys'],\n ['😮', 'surprised open mouth', 'smileys'],\n ['😲', 'astonished', 'smileys'],\n ['🥺', 'pleading begging puppy eyes', 'smileys'],\n ['😢', 'cry sad tear', 'smileys'],\n ['😭', 'sob cry loudly', 'smileys'],\n ['😱', 'scream horror fear', 'smileys'],\n ['😡', 'angry red pouting', 'smileys'],\n ['😠', 'angry mad', 'smileys'],\n ['🤬', 'cursing swear', 'smileys'],\n ['😈', 'devil evil smile', 'smileys'],\n ['👿', 'devil angry evil', 'smileys'],\n ['💀', 'skull death', 'smileys'],\n ['☠️', 'skull crossbones', 'smileys'],\n ['💩', 'poop', 'smileys'],\n ['🤡', 'clown', 'smileys'],\n ['👻', 'ghost boo', 'smileys'],\n ['👽', 'alien ufo', 'smileys'],\n ['🤖', 'robot', 'smileys'],\n\n // People & Body\n ['👋', 'wave hello hi hand', 'people'],\n ['🤚', 'raised back hand', 'people'],\n ['✋', 'raised hand stop', 'people'],\n ['🖖', 'vulcan salute spock', 'people'],\n ['👌', 'ok perfect fine', 'people'],\n ['✌️', 'peace victory fingers', 'people'],\n ['🤞', 'fingers crossed luck', 'people'],\n ['🤟', 'love you gesture', 'people'],\n ['🤘', 'sign of horns rock', 'people'],\n ['🤙', 'call me hand', 'people'],\n ['👈', 'point left', 'people'],\n ['👉', 'point right', 'people'],\n ['👆', 'point up', 'people'],\n ['👇', 'point down', 'people'],\n ['☝️', 'index pointing up', 'people'],\n ['👍', 'thumbs up like good', 'people'],\n ['👎', 'thumbs down dislike bad', 'people'],\n ['✊', 'raised fist punch', 'people'],\n ['👊', 'oncoming fist punch', 'people'],\n ['👏', 'clap applause', 'people'],\n ['🙌', 'celebrate raise hands', 'people'],\n ['🤝', 'handshake deal', 'people'],\n ['🙏', 'pray hope please thanks', 'people'],\n ['💅', 'nail polish', 'people'],\n ['💪', 'flexed bicep strong muscle', 'people'],\n ['👀', 'eyes look see', 'people'],\n ['👁️', 'eye', 'people'],\n ['👅', 'tongue', 'people'],\n ['👶', 'baby', 'people'],\n ['🧒', 'child', 'people'],\n ['👦', 'boy', 'people'],\n ['👧', 'girl', 'people'],\n ['🧑', 'person adult', 'people'],\n ['👨', 'man', 'people'],\n ['👩', 'woman', 'people'],\n ['🧔', 'beard man', 'people'],\n ['🧓', 'older person', 'people'],\n ['👴', 'old man', 'people'],\n ['👵', 'old woman', 'people'],\n ['❤️', 'heart love red', 'people'],\n ['🧡', 'orange heart love', 'people'],\n ['💛', 'yellow heart love', 'people'],\n ['💚', 'green heart love', 'people'],\n ['💙', 'blue heart love', 'people'],\n ['💜', 'purple heart love', 'people'],\n ['🖤', 'black heart', 'people'],\n ['🤍', 'white heart', 'people'],\n ['🤎', 'brown heart', 'people'],\n ['💔', 'broken heart', 'people'],\n ['❣️', 'exclamation heart', 'people'],\n ['💕', 'two hearts love', 'people'],\n ['💞', 'revolving hearts', 'people'],\n ['💓', 'beating heart', 'people'],\n ['💗', 'growing heart', 'people'],\n ['💖', 'sparkling heart', 'people'],\n ['💘', 'heart arrow', 'people'],\n ['💝', 'heart ribbon', 'people'],\n ['💬', 'speech bubble comment chat', 'people'],\n ['💭', 'thought bubble', 'people'],\n ['💯', '100 hundred percent perfect', 'people'],\n ['💢', 'anger symbol mad', 'people'],\n ['💤', 'zzz sleep', 'people'],\n\n // Animals & Nature\n ['🐶', 'dog puppy', 'animals'],\n ['🐱', 'cat kitten', 'animals'],\n ['🐭', 'mouse', 'animals'],\n ['🐹', 'hamster', 'animals'],\n ['🐰', 'rabbit bunny', 'animals'],\n ['🦊', 'fox', 'animals'],\n ['🐻', 'bear', 'animals'],\n ['🐼', 'panda', 'animals'],\n ['🐨', 'koala', 'animals'],\n ['🐯', 'tiger', 'animals'],\n ['🦁', 'lion', 'animals'],\n ['🐮', 'cow', 'animals'],\n ['🐷', 'pig', 'animals'],\n ['🐸', 'frog', 'animals'],\n ['🐵', 'monkey', 'animals'],\n ['🙈', 'see no evil monkey', 'animals'],\n ['🙉', 'hear no evil monkey', 'animals'],\n ['🙊', 'speak no evil monkey', 'animals'],\n ['🐔', 'chicken hen', 'animals'],\n ['🐧', 'penguin', 'animals'],\n ['🐦', 'bird', 'animals'],\n ['🦆', 'duck', 'animals'],\n ['🦅', 'eagle', 'animals'],\n ['🦉', 'owl', 'animals'],\n ['🦇', 'bat', 'animals'],\n ['🐺', 'wolf', 'animals'],\n ['🐴', 'horse', 'animals'],\n ['🦄', 'unicorn', 'animals'],\n ['🐝', 'bee', 'animals'],\n ['🦋', 'butterfly', 'animals'],\n ['🐌', 'snail', 'animals'],\n ['🐞', 'ladybug', 'animals'],\n ['🐢', 'turtle', 'animals'],\n ['🐍', 'snake', 'animals'],\n ['🦎', 'lizard', 'animals'],\n ['🐊', 'crocodile', 'animals'],\n ['🐟', 'fish', 'animals'],\n ['🐠', 'tropical fish', 'animals'],\n ['🦈', 'shark', 'animals'],\n ['🐬', 'dolphin', 'animals'],\n ['🐳', 'whale', 'animals'],\n ['🐙', 'octopus', 'animals'],\n ['🦑', 'squid', 'animals'],\n ['🦀', 'crab', 'animals'],\n ['🌸', 'cherry blossom flower', 'animals'],\n ['🌺', 'hibiscus flower', 'animals'],\n ['🌻', 'sunflower', 'animals'],\n ['🌹', 'rose flower', 'animals'],\n ['🌷', 'tulip flower', 'animals'],\n ['🍀', 'four leaf clover luck', 'animals'],\n ['🌿', 'herb leaf green', 'animals'],\n ['🌱', 'seedling sprout', 'animals'],\n ['🌲', 'evergreen tree pine', 'animals'],\n ['🌳', 'deciduous tree', 'animals'],\n ['🌴', 'palm tree', 'animals'],\n ['🍄', 'mushroom', 'animals'],\n ['🌾', 'sheaf wheat', 'animals'],\n ['🐾', 'paw prints animal', 'animals'],\n\n // Food & Drink\n ['🍎', 'apple red', 'food'],\n ['🍊', 'orange tangerine', 'food'],\n ['🍋', 'lemon yellow', 'food'],\n ['🍇', 'grapes', 'food'],\n ['🍓', 'strawberry', 'food'],\n ['🫐', 'blueberry', 'food'],\n ['🍒', 'cherry', 'food'],\n ['🍑', 'peach', 'food'],\n ['🥭', 'mango', 'food'],\n ['🍍', 'pineapple', 'food'],\n ['🥥', 'coconut', 'food'],\n ['🥝', 'kiwi', 'food'],\n ['🍅', 'tomato', 'food'],\n ['🥑', 'avocado', 'food'],\n ['🍆', 'eggplant aubergine', 'food'],\n ['🥕', 'carrot', 'food'],\n ['🌽', 'corn', 'food'],\n ['🥦', 'broccoli', 'food'],\n ['🥬', 'leafy green', 'food'],\n ['🧄', 'garlic', 'food'],\n ['🥜', 'peanut nut', 'food'],\n ['🍞', 'bread loaf', 'food'],\n ['🥐', 'croissant', 'food'],\n ['🧀', 'cheese', 'food'],\n ['🍳', 'egg fry cooking', 'food'],\n ['🥚', 'egg', 'food'],\n ['🥞', 'pancake', 'food'],\n ['🧇', 'waffle', 'food'],\n ['🥓', 'bacon', 'food'],\n ['🥩', 'meat steak', 'food'],\n ['🍗', 'chicken leg', 'food'],\n ['🌭', 'hotdog', 'food'],\n ['🍔', 'burger hamburger', 'food'],\n ['🍟', 'fries french', 'food'],\n ['🍕', 'pizza', 'food'],\n ['🌮', 'taco', 'food'],\n ['🌯', 'burrito wrap', 'food'],\n ['🍜', 'noodles ramen', 'food'],\n ['🍝', 'spaghetti pasta', 'food'],\n ['🍣', 'sushi', 'food'],\n ['🍱', 'bento box', 'food'],\n ['🍦', 'ice cream soft serve', 'food'],\n ['🍩', 'donut', 'food'],\n ['🍪', 'cookie', 'food'],\n ['🎂', 'birthday cake', 'food'],\n ['🍰', 'cake slice', 'food'],\n ['🧁', 'cupcake', 'food'],\n ['🍫', 'chocolate', 'food'],\n ['🍬', 'candy', 'food'],\n ['🍭', 'lollipop', 'food'],\n ['☕', 'coffee hot', 'food'],\n ['🍵', 'tea hot', 'food'],\n ['🧋', 'bubble tea boba', 'food'],\n ['🥤', 'cup straw drink', 'food'],\n ['🍷', 'wine red', 'food'],\n ['🍸', 'cocktail martini', 'food'],\n ['🍺', 'beer mug', 'food'],\n ['🍻', 'clinking beer mugs', 'food'],\n ['🥂', 'champagne toast celebrate', 'food'],\n ['🧃', 'juice box', 'food'],\n ['🧊', 'ice cube', 'food'],\n\n // Travel & Places\n ['🚀', 'rocket space', 'travel'],\n ['🛸', 'ufo flying saucer', 'travel'],\n ['✈️', 'airplane plane fly', 'travel'],\n ['🚁', 'helicopter', 'travel'],\n ['🚂', 'train locomotive', 'travel'],\n ['🚄', 'bullet train fast', 'travel'],\n ['🚇', 'subway metro', 'travel'],\n ['🚌', 'bus', 'travel'],\n ['🚑', 'ambulance', 'travel'],\n ['🚒', 'fire truck', 'travel'],\n ['🚓', 'police car', 'travel'],\n ['🚕', 'taxi cab', 'travel'],\n ['🚗', 'car automobile red', 'travel'],\n ['🚙', 'suv car', 'travel'],\n ['🚚', 'truck delivery', 'travel'],\n ['🚜', 'tractor farm', 'travel'],\n ['🏎️', 'racing car fast', 'travel'],\n ['🏍️', 'motorcycle', 'travel'],\n ['🚲', 'bicycle bike', 'travel'],\n ['🛴', 'scooter kick', 'travel'],\n ['⛵', 'sailboat boat', 'travel'],\n ['🚢', 'ship cruise', 'travel'],\n ['🏠', 'house home', 'travel'],\n ['🏢', 'office building', 'travel'],\n ['🏥', 'hospital', 'travel'],\n ['🏦', 'bank', 'travel'],\n ['🏪', 'store shop convenience', 'travel'],\n ['🏫', 'school', 'travel'],\n ['🏰', 'castle european', 'travel'],\n ['🏯', 'japanese castle', 'travel'],\n ['🗼', 'tokyo tower', 'travel'],\n ['🗽', 'statue liberty new york', 'travel'],\n ['⛪', 'church', 'travel'],\n ['🕌', 'mosque', 'travel'],\n ['⛩️', 'shinto shrine', 'travel'],\n ['⛲', 'fountain', 'travel'],\n ['⛺', 'tent camping', 'travel'],\n ['🌁', 'fog foggy bridge', 'travel'],\n ['🌃', 'night city stars', 'travel'],\n ['🏙️', 'cityscape city buildings', 'travel'],\n ['🌅', 'sunrise morning', 'travel'],\n ['🌈', 'rainbow colorful', 'travel'],\n ['⛰️', 'mountain', 'travel'],\n ['🏔️', 'snow mountain', 'travel'],\n ['🗻', 'mount fuji', 'travel'],\n ['🏕️', 'camping tent', 'travel'],\n ['🗺️', 'world map', 'travel'],\n ['🧭', 'compass navigation', 'travel'],\n ['🌍', 'earth europe africa globe', 'travel'],\n ['🌎', 'earth americas globe', 'travel'],\n ['🌏', 'earth asia globe', 'travel'],\n ['🌐', 'globe internet web', 'travel'],\n\n // Objects\n ['💎', 'diamond gem jewel', 'objects'],\n ['💍', 'ring engagement', 'objects'],\n ['👑', 'crown royal king queen', 'objects'],\n ['🎩', 'top hat magic', 'objects'],\n ['💼', 'briefcase work business', 'objects'],\n ['👜', 'handbag purse', 'objects'],\n ['🎒', 'backpack bag school', 'objects'],\n ['👓', 'glasses eyewear', 'objects'],\n ['🕶️', 'sunglasses cool', 'objects'],\n ['💡', 'light bulb idea', 'objects'],\n ['🔦', 'flashlight torch', 'objects'],\n ['🕯️', 'candle light', 'objects'],\n ['🔋', 'battery charge', 'objects'],\n ['💻', 'laptop computer', 'objects'],\n ['🖥️', 'desktop monitor computer', 'objects'],\n ['📱', 'phone mobile cell', 'objects'],\n ['⌨️', 'keyboard type', 'objects'],\n ['🖱️', 'mouse computer click', 'objects'],\n ['📺', 'television tv', 'objects'],\n ['📷', 'camera photo', 'objects'],\n ['📹', 'video camera', 'objects'],\n ['🎥', 'movie camera film', 'objects'],\n ['☎️', 'telephone phone', 'objects'],\n ['⏰', 'alarm clock wake', 'objects'],\n ['⌚', 'watch time', 'objects'],\n ['🔑', 'key', 'objects'],\n ['🗝️', 'old key', 'objects'],\n ['🔒', 'lock closed', 'objects'],\n ['🔓', 'unlock open', 'objects'],\n ['🔨', 'hammer tool', 'objects'],\n ['🔧', 'wrench tool', 'objects'],\n ['🔩', 'bolt nut', 'objects'],\n ['⚙️', 'gear setting', 'objects'],\n ['🧲', 'magnet attract', 'objects'],\n ['📚', 'books stack library', 'objects'],\n ['📖', 'book open read', 'objects'],\n ['📝', 'memo write note', 'objects'],\n ['✏️', 'pencil write edit', 'objects'],\n ['📌', 'pushpin tack', 'objects'],\n ['📎', 'paperclip attach', 'objects'],\n ['📊', 'bar chart graph', 'objects'],\n ['📈', 'chart up growth trend', 'objects'],\n ['📉', 'chart down loss decline', 'objects'],\n ['📅', 'calendar date', 'objects'],\n ['📦', 'package box', 'objects'],\n ['📫', 'mailbox closed', 'objects'],\n ['📧', 'email envelope', 'objects'],\n ['🎁', 'gift present', 'objects'],\n ['🎀', 'ribbon bow', 'objects'],\n ['🎉', 'party celebrate confetti', 'objects'],\n ['🎊', 'confetti celebrate', 'objects'],\n ['🔮', 'crystal ball magic fortune', 'objects'],\n ['🪄', 'magic wand', 'objects'],\n ['🎯', 'target bullseye dart', 'objects'],\n ['🎲', 'dice game board', 'objects'],\n ['🎮', 'video game controller', 'objects'],\n ['🎭', 'theater masks drama', 'objects'],\n ['🎨', 'art palette paint', 'objects'],\n ['🎬', 'clapper film movie', 'objects'],\n ['🎤', 'microphone sing karaoke', 'objects'],\n ['🎧', 'headphones music listen', 'objects'],\n ['🎵', 'music note', 'objects'],\n ['🎶', 'music notes', 'objects'],\n ['🎸', 'guitar electric', 'objects'],\n ['🎹', 'piano keyboard music', 'objects'],\n ['🥁', 'drum percussion', 'objects'],\n ['🎷', 'saxophone jazz', 'objects'],\n ['🎺', 'trumpet', 'objects'],\n ['🎻', 'violin', 'objects'],\n ['⚽', 'soccer ball football', 'objects'],\n ['🏀', 'basketball', 'objects'],\n ['🏈', 'american football', 'objects'],\n ['⚾', 'baseball', 'objects'],\n ['🎾', 'tennis', 'objects'],\n ['🏐', 'volleyball', 'objects'],\n ['🏆', 'trophy winner award', 'objects'],\n ['🥇', 'gold medal first', 'objects'],\n ['🏅', 'sports medal', 'objects'],\n\n // Symbols\n ['✅', 'check green done success', 'symbols'],\n ['❌', 'cross x no cancel', 'symbols'],\n ['⭕', 'circle red', 'symbols'],\n ['⛔', 'no entry stop', 'symbols'],\n ['🚫', 'prohibited no banned', 'symbols'],\n ['⚠️', 'warning caution danger', 'symbols'],\n ['❗', 'exclamation red important', 'symbols'],\n ['❓', 'question mark', 'symbols'],\n ['‼️', 'double exclamation', 'symbols'],\n ['💯', '100 hundred percent perfect', 'symbols'],\n ['🔴', 'red circle dot', 'symbols'],\n ['🟠', 'orange circle', 'symbols'],\n ['🟡', 'yellow circle', 'symbols'],\n ['🟢', 'green circle', 'symbols'],\n ['🔵', 'blue circle', 'symbols'],\n ['🟣', 'purple circle', 'symbols'],\n ['⚫', 'black circle', 'symbols'],\n ['⚪', 'white circle', 'symbols'],\n ['🟤', 'brown circle', 'symbols'],\n ['🔺', 'red triangle up', 'symbols'],\n ['🔻', 'red triangle down', 'symbols'],\n ['🔷', 'blue diamond large', 'symbols'],\n ['🔶', 'orange diamond large', 'symbols'],\n ['🔹', 'blue diamond small', 'symbols'],\n ['🔸', 'orange diamond small', 'symbols'],\n ['⭐', 'star yellow', 'symbols'],\n ['🌟', 'glowing star shine', 'symbols'],\n ['✨', 'sparkles shine', 'symbols'],\n ['💫', 'dizzy star spin', 'symbols'],\n ['⚡', 'lightning bolt energy power', 'symbols'],\n ['🔥', 'fire hot flame', 'symbols'],\n ['💥', 'explosion boom', 'symbols'],\n ['❄️', 'snowflake cold ice winter', 'symbols'],\n ['🌊', 'wave water ocean sea', 'symbols'],\n ['💨', 'wind blow dash', 'symbols'],\n ['🌀', 'cyclone tornado spiral', 'symbols'],\n ['♻️', 'recycle loop green', 'symbols'],\n ['✔️', 'check tick done', 'symbols'],\n ['➕', 'plus add', 'symbols'],\n ['➖', 'minus subtract', 'symbols'],\n ['➗', 'divide division', 'symbols'],\n ['✖️', 'multiply times cross', 'symbols'],\n ['▶️', 'play button right', 'symbols'],\n ['⏸️', 'pause', 'symbols'],\n ['⏹️', 'stop square', 'symbols'],\n ['⏩', 'fast forward', 'symbols'],\n ['⏪', 'rewind fast backward', 'symbols'],\n ['🔔', 'bell notification', 'symbols'],\n ['🔕', 'bell slash mute', 'symbols'],\n ['🔊', 'speaker volume high', 'symbols'],\n ['🔇', 'mute silent no sound', 'symbols'],\n ['📢', 'loudspeaker announcement', 'symbols'],\n ['📣', 'megaphone cheer', 'symbols'],\n ['🏳️', 'white flag', 'symbols'],\n ['🏴', 'black flag', 'symbols'],\n ['🚩', 'red flag', 'symbols'],\n ['🏁', 'checkered flag finish race', 'symbols'],\n ['🆕', 'new badge', 'symbols'],\n ['🆓', 'free badge', 'symbols'],\n ['🆒', 'cool badge', 'symbols'],\n ['🔝', 'top arrow', 'symbols'],\n ['🔙', 'back arrow', 'symbols'],\n ['ℹ️', 'information info', 'symbols'],\n ['📍', 'pin location map', 'symbols'],\n ['🔗', 'link chain', 'symbols'],\n ['©️', 'copyright', 'symbols'],\n ['®️', 'registered trademark', 'symbols'],\n ['™️', 'trademark', 'symbols'],\n ['#️⃣', 'hash number', 'symbols'],\n ['0️⃣', 'zero number', 'symbols'],\n ['1️⃣', 'one number', 'symbols'],\n ['2️⃣', 'two number', 'symbols'],\n ['3️⃣', 'three number', 'symbols'],\n ['4️⃣', 'four number', 'symbols'],\n ['5️⃣', 'five number', 'symbols'],\n];\n\n"],"mappings":"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AkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAK;EAAkC;CAAQ;CAChD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAO;EAAiC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAiC;CAAQ;CAChD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CAGjD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAkC;CAAS;CAGlD;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAK;EAAkC;CAAM;CAC9C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAC/C;EAAC;EAAM;EAAkC;CAAM;CAG/C;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAO;EAAkC;CAAQ;CAClD;EAAC;EAAO;EAAkC;CAAQ;CAClD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAK;EAAkC;CAAQ;CAChD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAK;EAAkC;CAAQ;CAChD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAK;EAAkC;CAAQ;CAChD;EAAC;EAAK;EAAkC;CAAQ;CAChD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAO;EAAkC;CAAQ;CAClD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAO;EAAkC;CAAQ;CAClD;EAAC;EAAM;EAAkC;CAAQ;CACjD;EAAC;EAAO;EAAkC;CAAQ;CAClD;EAAC;EAAO;EAAkC;CAAQ;CAClD;EAAC;EAAM;EAAkC;CA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;CAAS;CACjD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAM;EAAkC;CAAS;CAClD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAK;EAAiC;CAAS;CAChD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAO;EAAiC;CAAS;CAClD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAM;EAAiC;CAAS;CACjD;EAAC;EAAO;EAAgC;CAAS;CACjD;EAAC;EAAO;EAAgC;CAAS;CACjD;EAAC;EAAO;EAAgC;CAAS;CACjD;EAAC;EAAO;EAAgC;CAAS;CACjD;EAAC;EAAO;EAAgC;CAAS;CACjD;EAAC;EAAO;EAAgC;CAAS;CACjD;EAAC;EAAO;EAAgC;CAAS;CACjD;EAAC;EAAO;EAAgC;CAAS;CACjD;EAAC;EAAO;EAAgC;CAAS;CACjD;EAAC;EAAO;EAAgC;CAAS;AACnD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autumnnote",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "WYSIWYG rich-text editor built with vanilla JavaScript — zero dependencies, no jQuery. Dark mode, @mention, markdown shortcuts, bubble toolbar. React and Vue 3 wrappers included.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/autumnnote.cjs",
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
"import": "./dist/autumnnote.es.js",
|
|
14
14
|
"require": "./dist/autumnnote.cjs"
|
|
15
15
|
},
|
|
16
|
+
"./i18n/*": {
|
|
17
|
+
"types": "./types/i18n/*.d.ts",
|
|
18
|
+
"import": "./src/js/i18n/*.js"
|
|
19
|
+
},
|
|
16
20
|
"./dist/autumnnote.css": "./dist/autumnnote.css"
|
|
17
21
|
},
|
|
18
22
|
"files": [
|
|
@@ -100,7 +104,7 @@
|
|
|
100
104
|
"@vitest/browser-playwright": "^4.1.10",
|
|
101
105
|
"@vitest/coverage-v8": "^4.1.8",
|
|
102
106
|
"cross-env": "^10.1.0",
|
|
103
|
-
"eslint": "10.7.0",
|
|
107
|
+
"eslint": "^10.7.0",
|
|
104
108
|
"jsdom": "^25.0.1",
|
|
105
109
|
"playwright": "^1.61.1",
|
|
106
110
|
"rollup-plugin-visualizer": "^7.0.1",
|
package/src/js/Context.js
CHANGED
|
@@ -44,6 +44,21 @@ import { SlashMenu } from './module/SlashMenu.js';
|
|
|
44
44
|
/** Module registry shared across all Context instances (populated via AutumnNote.registerModule). */
|
|
45
45
|
export const _customModules = new Map();
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Modules whose registration depends on an option value. Declared once so the
|
|
49
|
+
* initial mount (`_registerModules`) and runtime toggles (`updateOptions`) can
|
|
50
|
+
* never drift apart — previously `updateOptions({ bubbleToolbar: true })`
|
|
51
|
+
* changed the option but silently left the module unregistered.
|
|
52
|
+
* @type {Array<{ name: string, Class: new (ctx: Context) => { initialize: () => any, destroy?: () => void }, enabled: (options: any) => boolean }>}
|
|
53
|
+
*/
|
|
54
|
+
const OPTIONAL_MODULES = [
|
|
55
|
+
{ name: 'autoSaveRestore', Class: AutoSaveRestore, enabled: (o) => !!o.autoSaveRestore },
|
|
56
|
+
{ name: 'markdownShortcuts', Class: MarkdownShortcuts, enabled: (o) => o.markdownShortcuts !== false },
|
|
57
|
+
{ name: 'bubbleToolbar', Class: BubbleToolbar, enabled: (o) => !!o.bubbleToolbar },
|
|
58
|
+
{ name: 'mention', Class: Mention, enabled: (o) => !!o.mention },
|
|
59
|
+
{ name: 'slashMenu', Class: SlashMenu, enabled: (o) => o.slashMenu !== false },
|
|
60
|
+
];
|
|
61
|
+
|
|
47
62
|
/** Global plugin registry (populated via AutumnNote.use()). Applied to every new Context. */
|
|
48
63
|
export const _globalPlugins = new Map();
|
|
49
64
|
|
|
@@ -76,6 +91,8 @@ export class Context {
|
|
|
76
91
|
this._autoSaveTimer = null;
|
|
77
92
|
this._pendingAutoSave = null;
|
|
78
93
|
this._suppressedRemoteHTML = null;
|
|
94
|
+
/** @type {Promise<void>|null} Settles when destroy()'s closing auto-save finishes */
|
|
95
|
+
this._destroyPromise = null;
|
|
79
96
|
}
|
|
80
97
|
|
|
81
98
|
// ---------------------------------------------------------------------------
|
|
@@ -157,11 +174,9 @@ export class Context {
|
|
|
157
174
|
register('shortcutsDialog', ShortcutsDialog);
|
|
158
175
|
register('findReplace', FindReplace);
|
|
159
176
|
register('imageCropOverlay', ImageCropOverlay);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (this.options.mention) register('mention', Mention);
|
|
164
|
-
if (this.options.slashMenu !== false) register('slashMenu', SlashMenu);
|
|
177
|
+
for (const { name, Class, enabled } of OPTIONAL_MODULES) {
|
|
178
|
+
if (enabled(this.options)) register(name, Class);
|
|
179
|
+
}
|
|
165
180
|
|
|
166
181
|
// Custom modules registered via AutumnNote.registerModule()
|
|
167
182
|
if (_customModules.size > 0) {
|
|
@@ -171,6 +186,29 @@ export class Context {
|
|
|
171
186
|
}
|
|
172
187
|
}
|
|
173
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Registers or tears down option-gated modules so they match the current
|
|
191
|
+
* option values. Called after `updateOptions()` so toggling e.g.
|
|
192
|
+
* `bubbleToolbar` at runtime actually takes effect.
|
|
193
|
+
*/
|
|
194
|
+
_syncOptionalModules() {
|
|
195
|
+
for (const { name, Class, enabled } of OPTIONAL_MODULES) {
|
|
196
|
+
const shouldRun = enabled(this.options);
|
|
197
|
+
const isRunning = this._modules.has(name);
|
|
198
|
+
if (shouldRun === isRunning) continue;
|
|
199
|
+
|
|
200
|
+
if (shouldRun) {
|
|
201
|
+
const instance = new Class(this);
|
|
202
|
+
this._modules.set(name, instance);
|
|
203
|
+
instance.initialize();
|
|
204
|
+
} else {
|
|
205
|
+
const instance = this._modules.get(name);
|
|
206
|
+
if (typeof instance?.destroy === 'function') instance.destroy();
|
|
207
|
+
this._modules.delete(name);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
174
212
|
/**
|
|
175
213
|
* Registers and initialises a custom module on this instance.
|
|
176
214
|
* @param {string} name
|
|
@@ -412,6 +450,9 @@ export class Context {
|
|
|
412
450
|
editable.style.maxHeight = this.options.maxHeight ? `${this.options.maxHeight}px` : '';
|
|
413
451
|
}
|
|
414
452
|
if (Object.hasOwn(overrides, 'toolbar')) this.invoke('toolbar.rebuild');
|
|
453
|
+
// Start/stop option-gated modules (bubbleToolbar, mention, slashMenu, ...)
|
|
454
|
+
// so toggling them here behaves the same as passing them to create().
|
|
455
|
+
this._syncOptionalModules();
|
|
415
456
|
this.invoke('statusbar.update');
|
|
416
457
|
this.triggerEvent('optionsChange', { ...overrides });
|
|
417
458
|
return this;
|
|
@@ -735,11 +776,23 @@ export class Context {
|
|
|
735
776
|
|
|
736
777
|
/**
|
|
737
778
|
* Completely removes the editor and restores the original element.
|
|
779
|
+
*
|
|
780
|
+
* Teardown itself is synchronous; the returned promise only settles once the
|
|
781
|
+
* closing auto-save has finished, so `await editor.destroy()` is worth doing
|
|
782
|
+
* when using an async `autoSaveAdapter`. Ignoring the return value is safe.
|
|
783
|
+
* @returns {Promise<void>}
|
|
738
784
|
*/
|
|
739
785
|
destroy() {
|
|
740
|
-
if (!this._alive) return;
|
|
786
|
+
if (!this._alive) return this._destroyPromise ?? Promise.resolve();
|
|
787
|
+
|
|
788
|
+
// Start the final auto-save before tearing anything down. `_listeners` is
|
|
789
|
+
// deliberately kept alive until this settles, otherwise the closing
|
|
790
|
+
// autoSave/autoSaveError event fires into an already-cleared listener map
|
|
791
|
+
// and an async adapter's last write completes silently.
|
|
792
|
+
const pendingFlush = this._pendingAutoSave != null
|
|
793
|
+
? this.flushAutoSave().catch(() => {})
|
|
794
|
+
: null;
|
|
741
795
|
|
|
742
|
-
if (this._pendingAutoSave != null) void this.flushAutoSave();
|
|
743
796
|
this._modules.forEach((module) => {
|
|
744
797
|
if (typeof module.destroy === 'function') module.destroy();
|
|
745
798
|
});
|
|
@@ -776,7 +829,14 @@ export class Context {
|
|
|
776
829
|
}
|
|
777
830
|
|
|
778
831
|
this._alive = false;
|
|
779
|
-
|
|
832
|
+
|
|
833
|
+
// Resolves once the closing auto-save (if any) has finished. Callers using
|
|
834
|
+
// an async autoSaveAdapter can `await editor.destroy()` to be sure the last
|
|
835
|
+
// write landed before unloading.
|
|
836
|
+
this._destroyPromise = Promise.resolve(pendingFlush).then(() => {
|
|
837
|
+
this._listeners.clear();
|
|
838
|
+
});
|
|
839
|
+
return this._destroyPromise;
|
|
780
840
|
}
|
|
781
841
|
|
|
782
842
|
// ---------------------------------------------------------------------------
|
package/src/js/core/env.js
CHANGED
|
@@ -1,25 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* env.js - Environment / browser detection
|
|
3
3
|
* Inspired by Summernote's env.js
|
|
4
|
+
*
|
|
5
|
+
* Every field is a lazy getter rather than a value computed at module load.
|
|
6
|
+
* This module is re-exported from the package entry point, so reading
|
|
7
|
+
* `navigator` eagerly meant that merely `import`ing autumnnote threw
|
|
8
|
+
* `ReferenceError: navigator is not defined` under SSR on any runtime without
|
|
9
|
+
* a global `navigator` — including Node 20, which package.json still supports.
|
|
10
|
+
* Nothing inside the library reads these fields, so the crash happened before
|
|
11
|
+
* an editor was ever created.
|
|
4
12
|
*/
|
|
5
13
|
|
|
6
|
-
|
|
14
|
+
/** @returns {string} the current user agent, or '' when there is no navigator (SSR). */
|
|
15
|
+
function ua() {
|
|
16
|
+
return globalThis.navigator?.userAgent ?? '';
|
|
17
|
+
}
|
|
7
18
|
|
|
8
19
|
export const env = {
|
|
9
|
-
/** True if browser is Chrome */
|
|
10
|
-
isChrome
|
|
20
|
+
/** True if browser is Chrome (excludes Edge, whose UA also contains "Chrome/") */
|
|
21
|
+
get isChrome() { return /Chrome\//.test(ua()) && !/Edg\//.test(ua()); },
|
|
11
22
|
/** True if browser is Firefox */
|
|
12
|
-
isFF
|
|
23
|
+
get isFF() { return /Firefox\//.test(ua()); },
|
|
13
24
|
/** True if browser is Safari (not Chrome) */
|
|
14
|
-
isSafari
|
|
25
|
+
get isSafari() { return /^((?!chrome|android).)*safari/i.test(ua()); },
|
|
15
26
|
/** True if browser is Edge (Chromium) */
|
|
16
|
-
isEdge
|
|
27
|
+
get isEdge() { return /Edg\//.test(ua()); },
|
|
17
28
|
/** True if running on macOS */
|
|
18
|
-
isMac
|
|
29
|
+
get isMac() { return /Macintosh/.test(ua()); },
|
|
19
30
|
/** True if running on mobile */
|
|
20
|
-
isMobile
|
|
31
|
+
get isMobile() { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua()); },
|
|
21
32
|
/** True if touch is supported */
|
|
22
|
-
isTouch
|
|
33
|
+
get isTouch() {
|
|
34
|
+
return 'ontouchstart' in globalThis || (globalThis.navigator?.maxTouchPoints ?? 0) > 0;
|
|
35
|
+
},
|
|
23
36
|
/** Modifier key name depending on platform */
|
|
24
|
-
modifierKey
|
|
37
|
+
get modifierKey() { return /Macintosh/.test(ua()) ? 'metaKey' : 'ctrlKey'; },
|
|
25
38
|
};
|
package/src/js/core/sanitise.js
CHANGED
|
@@ -5,14 +5,49 @@
|
|
|
5
5
|
* DOM-parser based — no regex-based stripping of HTML (avoids bypass tricks).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Tags that are unconditionally removed from editor content.
|
|
10
|
+
*
|
|
11
|
+
* Beyond the obvious script hosts this covers two SVG/MathML-specific classes:
|
|
12
|
+
*
|
|
13
|
+
* - SMIL animation (`animate`, `set`, `animateTransform`, `animateMotion`)
|
|
14
|
+
* can rewrite an attribute *after* sanitisation finishes, so
|
|
15
|
+
* `<svg><a><animate attributeName="href" values="javascript:…">` survives an
|
|
16
|
+
* attribute-level filter untouched and still navigates on click. The editor
|
|
17
|
+
* only ever emits static `<svg>` icons, so animation is pure attack surface.
|
|
18
|
+
*
|
|
19
|
+
* - `mglyph` / `malignmark` / `annotation-xml` are HTML integration points
|
|
20
|
+
* inside the MathML namespace. They make the parser switch namespaces
|
|
21
|
+
* mid-tree, which is what lets a crafted fragment re-parse into different
|
|
22
|
+
* markup than it serialised from (mXSS). The rest of MathML is left alone so
|
|
23
|
+
* pasted formulae survive.
|
|
24
|
+
*/
|
|
25
|
+
const PROHIBITED_TAGS = [
|
|
26
|
+
'script', 'style', 'iframe', 'object', 'embed', 'form', 'base', 'template',
|
|
27
|
+
'link', 'meta', 'noscript', 'portal', 'frame', 'frameset', 'applet',
|
|
28
|
+
'animate', 'set', 'animatetransform', 'animatemotion',
|
|
29
|
+
'mglyph', 'malignmark', 'annotation-xml',
|
|
30
|
+
];
|
|
10
31
|
|
|
11
32
|
/** Tags whose element wrapper is stripped but content (child nodes) is preserved. */
|
|
12
33
|
const UNWRAP_TAGS = new Set(['button']);
|
|
13
34
|
|
|
14
35
|
/** Attributes whose values must be sanitised as URLs. */
|
|
15
|
-
const URL_ATTRS = ['href', 'src', 'action', 'formaction', 'xlink:href'];
|
|
36
|
+
const URL_ATTRS = ['href', 'src', 'action', 'formaction', 'xlink:href', 'poster', 'background', 'srcset'];
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* URL attributes that address media rather than navigation, so they are
|
|
40
|
+
* validated against SAFE_MEDIA_PROTOCOLS regardless of which element carries
|
|
41
|
+
* them (unlike `src`, whose meaning depends on the owning tag).
|
|
42
|
+
*/
|
|
43
|
+
const MEDIA_URL_ATTRS = new Set(['poster', 'background', 'srcset']);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Attributes removed outright: the editor never emits them and their only
|
|
47
|
+
* effect is an outbound request the author did not ask for. `ping` fires a
|
|
48
|
+
* POST beacon to arbitrary hosts when a link is clicked.
|
|
49
|
+
*/
|
|
50
|
+
const BEACON_ATTRS = new Set(['ping']);
|
|
16
51
|
|
|
17
52
|
/** Inline style properties the editor's own toolbar/table features persist on saved content. */
|
|
18
53
|
const ALLOWED_STYLE_PROPS = new Set([
|
|
@@ -22,8 +57,12 @@ const ALLOWED_STYLE_PROPS = new Set([
|
|
|
22
57
|
'border-width', 'border-style', 'border-color', 'padding',
|
|
23
58
|
]);
|
|
24
59
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Value patterns that are never safe regardless of property.
|
|
62
|
+
* `image-set()` and `src()` are covered alongside `url()` — all three fetch an
|
|
63
|
+
* external resource, so allowing them would let pasted content phone home.
|
|
64
|
+
*/
|
|
65
|
+
const DANGEROUS_STYLE_VALUE_RE = /url\s*\(|image-set\s*\(|src\s*\(|expression\s*\(|@import|javascript:|vbscript:|behavior\s*:|-moz-binding/i;
|
|
27
66
|
|
|
28
67
|
/** Trusted hosts for iframe embeds when allowIframes is enabled. */
|
|
29
68
|
const TRUSTED_IFRAME_HOSTS = new Set([
|
|
@@ -106,12 +145,21 @@ export function sanitiseHTML(html, { allowIframes = false } = {}) {
|
|
|
106
145
|
else el.removeAttribute('style');
|
|
107
146
|
continue;
|
|
108
147
|
}
|
|
148
|
+
// Drop tracking-beacon attributes outright
|
|
149
|
+
if (BEACON_ATTRS.has(attr.name)) {
|
|
150
|
+
el.removeAttribute(attr.name);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
109
153
|
// Sanitise URL attributes
|
|
110
154
|
if (URL_ATTRS.includes(attr.name)) {
|
|
111
155
|
const val = attr.value.trim();
|
|
112
|
-
const isMediaSource = attr.name
|
|
113
|
-
['IMG', 'VIDEO', 'AUDIO', 'SOURCE'].includes(el.tagName);
|
|
114
|
-
|
|
156
|
+
const isMediaSource = MEDIA_URL_ATTRS.has(attr.name) ||
|
|
157
|
+
(attr.name === 'src' && ['IMG', 'VIDEO', 'AUDIO', 'SOURCE'].includes(el.tagName));
|
|
158
|
+
const allowData = el.tagName === 'IMG';
|
|
159
|
+
const safe = attr.name === 'srcset'
|
|
160
|
+
? isSafeSrcset(val, { allowData })
|
|
161
|
+
: isSafeUrl(val, { media: isMediaSource, allowData });
|
|
162
|
+
if (!safe) {
|
|
115
163
|
el.removeAttribute(attr.name);
|
|
116
164
|
continue;
|
|
117
165
|
}
|
|
@@ -174,6 +222,31 @@ function sanitiseStyleValue(value) {
|
|
|
174
222
|
return kept.join('; ');
|
|
175
223
|
}
|
|
176
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Validates every candidate URL in a `srcset` attribute.
|
|
227
|
+
*
|
|
228
|
+
* Per the HTML srcset grammar a candidate URL is a run of non-whitespace
|
|
229
|
+
* characters — commas may appear *inside* it, which is why `data:` URLs work
|
|
230
|
+
* there — optionally followed by a width (`300w`) or density (`2x`) descriptor.
|
|
231
|
+
* Splitting on whitespace and skipping descriptor tokens therefore yields the
|
|
232
|
+
* URL set. Anything unparseable makes the whole attribute fail, since a
|
|
233
|
+
* partially-trusted candidate list is not something we can express.
|
|
234
|
+
*
|
|
235
|
+
* @param {string} value
|
|
236
|
+
* @param {{ allowData?: boolean }} [options]
|
|
237
|
+
* @returns {boolean}
|
|
238
|
+
*/
|
|
239
|
+
function isSafeSrcset(value, { allowData = false } = {}) {
|
|
240
|
+
const tokens = (value || '').trim().split(/\s+/).filter(Boolean);
|
|
241
|
+
for (const token of tokens) {
|
|
242
|
+
if (/^[\d.]+[xw],?$/i.test(token)) continue; // width/density descriptor
|
|
243
|
+
const url = token.replace(/,+$/, ''); // trailing comma = candidate separator
|
|
244
|
+
if (!url) continue;
|
|
245
|
+
if (!isSafeUrl(url, { media: true, allowData })) return false;
|
|
246
|
+
}
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
|
|
177
250
|
/**
|
|
178
251
|
* Returns true if iframe src points to an approved video host.
|
|
179
252
|
* Relative, protocol-relative and invalid URLs are rejected.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n/all.js — Registers every bundled locale.
|
|
3
|
+
*
|
|
4
|
+
* Imported by the UMD/CDN entry point, where script-tag consumers have no
|
|
5
|
+
* bundler to tree-shake with and therefore expect `lang: 'vi'` to work out of
|
|
6
|
+
* the box. ESM consumers should import only the locales they need from
|
|
7
|
+
* `autumnnote/i18n/<code>` instead of pulling this in.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { registerLocale } from './index.js';
|
|
11
|
+
import { vi } from './vi.js';
|
|
12
|
+
import { ja } from './ja.js';
|
|
13
|
+
import { zh } from './zh.js';
|
|
14
|
+
import { fr } from './fr.js';
|
|
15
|
+
import { de } from './de.js';
|
|
16
|
+
import { es } from './es.js';
|
|
17
|
+
import { ko } from './ko.js';
|
|
18
|
+
|
|
19
|
+
registerLocale('vi', vi);
|
|
20
|
+
registerLocale('ja', ja);
|
|
21
|
+
registerLocale('zh', zh);
|
|
22
|
+
registerLocale('fr', fr);
|
|
23
|
+
registerLocale('de', de);
|
|
24
|
+
registerLocale('es', es);
|
|
25
|
+
registerLocale('ko', ko);
|
|
26
|
+
|
|
27
|
+
export { vi, ja, zh, fr, de, es, ko };
|
package/src/js/i18n/index.js
CHANGED
|
@@ -1,33 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* i18n/index.js — Locale registry and resolver for autumn-note-ce.
|
|
3
3
|
*
|
|
4
|
+
* Only English ships in the ESM bundle. Bundling all eight locales cost every
|
|
5
|
+
* consumer ~15 KB gzip even when they only ever rendered English, so the other
|
|
6
|
+
* locales are opt-in via subpath imports:
|
|
7
|
+
*
|
|
8
|
+
* import AutumnNote from 'autumnnote';
|
|
9
|
+
* import { vi } from 'autumnnote/i18n/vi';
|
|
10
|
+
*
|
|
11
|
+
* AutumnNote.registerLocale('vi', vi);
|
|
12
|
+
* AutumnNote.create('#editor', { lang: 'vi' });
|
|
13
|
+
*
|
|
14
|
+
* The UMD/CDN build cannot tree-shake, so it pre-registers every locale and
|
|
15
|
+
* `lang: 'vi'` keeps working there with no extra imports.
|
|
16
|
+
*
|
|
4
17
|
* Usage:
|
|
5
|
-
* lang: 'en' → built-in English (
|
|
6
|
-
* lang: '
|
|
7
|
-
* lang: 'ja' → built-in Japanese
|
|
8
|
-
* lang: 'zh' → built-in Simplified Chinese
|
|
9
|
-
* lang: 'fr' → built-in French
|
|
10
|
-
* lang: 'de' → built-in German
|
|
11
|
-
* lang: 'es' → built-in Spanish
|
|
12
|
-
* lang: 'ko' → built-in Korean
|
|
18
|
+
* lang: 'en' → built-in English (always available)
|
|
19
|
+
* lang: '<code>' → a locale previously passed to registerLocale()
|
|
13
20
|
* lang: { ... } → custom locale object, deep-merged over English
|
|
14
21
|
*/
|
|
15
22
|
|
|
16
23
|
import { mergeDeep } from '../core/func.js';
|
|
17
24
|
import { en } from './en.js';
|
|
18
|
-
import { vi } from './vi.js';
|
|
19
|
-
import { ja } from './ja.js';
|
|
20
|
-
import { zh } from './zh.js';
|
|
21
|
-
import { fr } from './fr.js';
|
|
22
|
-
import { de } from './de.js';
|
|
23
|
-
import { es } from './es.js';
|
|
24
|
-
import { ko } from './ko.js';
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Locales available to `lang: '<code>'`. Starts with English only; other codes
|
|
28
|
+
* are added through {@link registerLocale}.
|
|
28
29
|
* @type {Record<string, Partial<AsnLocale>>}
|
|
29
30
|
*/
|
|
30
|
-
export const locales = { en
|
|
31
|
+
export const locales = { en };
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Registers a locale so it can be selected by code.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} code - Language code, e.g. 'vi'.
|
|
37
|
+
* @param {Partial<AsnLocale>} locale - Locale object; missing keys fall back to English.
|
|
38
|
+
* @returns {void}
|
|
39
|
+
*/
|
|
40
|
+
export function registerLocale(code, locale) {
|
|
41
|
+
if (typeof code !== 'string' || !code) {
|
|
42
|
+
throw new TypeError('[AutumnNote] registerLocale: code must be a non-empty string.');
|
|
43
|
+
}
|
|
44
|
+
if (!locale || typeof locale !== 'object') {
|
|
45
|
+
throw new TypeError(`[AutumnNote] registerLocale: locale for "${code}" must be an object.`);
|
|
46
|
+
}
|
|
47
|
+
locales[code] = locale;
|
|
48
|
+
}
|
|
31
49
|
|
|
32
50
|
/**
|
|
33
51
|
* Resolve a locale object from a lang option value.
|
|
@@ -41,8 +59,16 @@ export function resolveLocale(lang) {
|
|
|
41
59
|
|
|
42
60
|
if (typeof lang === 'string') {
|
|
43
61
|
const partial = locales[lang];
|
|
44
|
-
|
|
45
|
-
|
|
62
|
+
if (!partial) {
|
|
63
|
+
// Unregistered code → English, but say why: silently rendering English
|
|
64
|
+
// after asking for another language is confusing to debug.
|
|
65
|
+
console.warn(
|
|
66
|
+
`[AutumnNote] Locale "${lang}" is not registered, falling back to English. ` +
|
|
67
|
+
`Import it first: import { ${lang} } from 'autumnnote/i18n/${lang}'; ` +
|
|
68
|
+
`AutumnNote.registerLocale('${lang}', ${lang});`,
|
|
69
|
+
);
|
|
70
|
+
return en;
|
|
71
|
+
}
|
|
46
72
|
return mergeDeep(mergeDeep({}, en), partial);
|
|
47
73
|
}
|
|
48
74
|
|
package/src/js/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import '../styles/autumnnote.scss';
|
|
|
14
14
|
import { Context, _customModules, _globalPlugins } from './Context.js';
|
|
15
15
|
import { registerButton, buttons } from './module/Buttons.js';
|
|
16
16
|
import { defaultOptions } from './settings.js';
|
|
17
|
+
import { registerLocale } from './i18n/index.js';
|
|
17
18
|
|
|
18
19
|
// Snapshot of factory defaults taken at module-load time (before any setDefaults() calls)
|
|
19
20
|
const _originalDefaults = { ...defaultOptions };
|
|
@@ -29,7 +30,7 @@ export * from './core/lists.js';
|
|
|
29
30
|
export * from './core/env.js';
|
|
30
31
|
export * from './core/sanitise.js';
|
|
31
32
|
export * from './module/Buttons.js';
|
|
32
|
-
export { locales, resolveLocale } from './i18n/index.js';
|
|
33
|
+
export { locales, resolveLocale, registerLocale } from './i18n/index.js';
|
|
33
34
|
|
|
34
35
|
// ---------------------------------------------------------------------------
|
|
35
36
|
// Main factory
|
|
@@ -140,6 +141,15 @@ const AutumnNote = {
|
|
|
140
141
|
*/
|
|
141
142
|
registerButton(btnDef) { registerButton(btnDef); return this; },
|
|
142
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Registers a locale so `lang: '<code>'` can select it.
|
|
146
|
+
* Only English ships in the ESM bundle — import others from
|
|
147
|
+
* `autumnnote/i18n/<code>` and register them here.
|
|
148
|
+
* @param {string} code
|
|
149
|
+
* @param {object} locale
|
|
150
|
+
*/
|
|
151
|
+
registerLocale(code, locale) { registerLocale(code, locale); return this; },
|
|
152
|
+
|
|
143
153
|
/** Registers a slash-menu command for future editor instances. */
|
|
144
154
|
registerSlashCommand(command) {
|
|
145
155
|
if (!command?.id || typeof command.run !== 'function') {
|
|
@@ -156,7 +166,7 @@ const AutumnNote = {
|
|
|
156
166
|
buttons,
|
|
157
167
|
|
|
158
168
|
/** Library version */
|
|
159
|
-
version: '1.
|
|
169
|
+
version: '2.1.0',
|
|
160
170
|
};
|
|
161
171
|
|
|
162
172
|
// ---------------------------------------------------------------------------
|
package/src/js/index.umd.js
CHANGED
|
@@ -9,4 +9,9 @@
|
|
|
9
9
|
* const editor = AutumnNote.create('#my-editor');
|
|
10
10
|
* </script>
|
|
11
11
|
*/
|
|
12
|
+
// Script-tag consumers have no bundler to tree-shake with, so every locale is
|
|
13
|
+
// pre-registered here and `lang: 'vi'` works without extra imports. ESM
|
|
14
|
+
// consumers opt in per locale via `autumnnote/i18n/<code>` instead.
|
|
15
|
+
import './i18n/all.js';
|
|
16
|
+
|
|
12
17
|
export { default } from './index.js';
|