@kissmybutton/mc-code 0.0.1

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.
@@ -0,0 +1,363 @@
1
+ import { BrowserClip, Effect } from '@donkeyclip/motorcortex';
2
+
3
+ /**
4
+ * CodeClip — a BrowserClip that renders syntax-highlighted code.
5
+ *
6
+ * Each line gets id: line_0, line_1, ... for targeting.
7
+ * Registers custom entity "code" for Effects via !#code.
8
+ *
9
+ * Attrs:
10
+ * code: string — the source code to display
11
+ * language: string (default: "javascript")
12
+ * theme: "dark" | "light" (default: "dark")
13
+ * fontSize: number (default: 14)
14
+ */
15
+
16
+ const THEMES = {
17
+ dark: {
18
+ bg: "#1e1e2e",
19
+ fg: "#cdd6f4",
20
+ lineNum: "#585b70",
21
+ keyword: "#cba6f7",
22
+ string: "#a6e3a1",
23
+ comment: "#6c7086",
24
+ fn: "#89b4fa",
25
+ number: "#fab387",
26
+ punct: "#94e2d5",
27
+ type: "#f9e2af"
28
+ },
29
+ light: {
30
+ bg: "#fafafa",
31
+ fg: "#383a42",
32
+ lineNum: "#9ca0b0",
33
+ keyword: "#a626a4",
34
+ string: "#50a14f",
35
+ comment: "#a0a1a7",
36
+ fn: "#4078f2",
37
+ number: "#986801",
38
+ punct: "#0184bc",
39
+ type: "#c18401"
40
+ }
41
+ };
42
+ const LANG_KEYWORDS = {
43
+ javascript: new Set(["const", "let", "var", "function", "return", "if", "else", "for", "while", "do", "switch", "case", "break", "continue", "new", "this", "class", "extends", "import", "export", "default", "from", "of", "in", "typeof", "instanceof", "try", "catch", "finally", "throw", "async", "await", "yield", "null", "undefined", "true", "false"]),
44
+ typescript: new Set(["const", "let", "var", "function", "return", "if", "else", "for", "while", "do", "switch", "case", "break", "continue", "new", "this", "class", "extends", "import", "export", "default", "from", "of", "in", "typeof", "instanceof", "try", "catch", "finally", "throw", "async", "await", "yield", "null", "undefined", "true", "false", "type", "interface", "enum", "implements", "declare", "readonly", "as", "is", "keyof", "never", "unknown", "any", "void", "abstract", "override", "satisfies", "infer"]),
45
+ python: new Set(["def", "return", "if", "elif", "else", "for", "while", "in", "not", "and", "or", "is", "class", "import", "from", "as", "with", "try", "except", "finally", "raise", "pass", "break", "continue", "yield", "lambda", "None", "True", "False", "self", "print", "range", "len", "dict", "list", "set", "tuple", "int", "str", "float", "bool", "async", "await"]),
46
+ bash: new Set(["if", "then", "else", "elif", "fi", "for", "do", "done", "while", "until", "case", "esac", "function", "return", "in", "echo", "exit", "export", "source", "local", "readonly", "declare", "set", "unset", "shift", "cd", "pwd", "ls", "grep", "sed", "awk", "cat", "mkdir", "rm", "cp", "mv", "chmod", "chown", "sudo", "apt", "yum", "npm", "pip", "git", "docker", "kubectl"]),
47
+ html: new Set(["div", "span", "p", "a", "img", "ul", "ol", "li", "h1", "h2", "h3", "h4", "h5", "h6", "table", "tr", "td", "th", "form", "input", "button", "select", "option", "textarea", "label", "header", "footer", "nav", "main", "section", "article", "aside", "script", "style", "link", "meta", "head", "body", "html"]),
48
+ css: new Set(["color", "background", "border", "margin", "padding", "display", "position", "width", "height", "font", "text", "flex", "grid", "align", "justify", "overflow", "opacity", "transform", "transition", "animation", "z-index", "top", "left", "right", "bottom", "none", "auto", "inherit", "initial", "important"])
49
+ };
50
+
51
+ // JSON/YAML don't have keywords in the traditional sense — handled by tokenizer rules
52
+ const COMMENT_STYLES = {
53
+ javascript: "//",
54
+ typescript: "//",
55
+ python: "#",
56
+ bash: "#",
57
+ yaml: "#",
58
+ css: null,
59
+ json: null,
60
+ html: null
61
+ };
62
+ function escapeHtml(s) {
63
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
64
+ }
65
+ function tokenizeLine(line, theme, language) {
66
+ const t = theme;
67
+ const keywords = LANG_KEYWORDS[language] || LANG_KEYWORDS.javascript;
68
+ const commentChar = COMMENT_STYLES[language] ?? "//";
69
+ let result = "";
70
+ let i = 0;
71
+
72
+ // YAML/JSON: color keys specially
73
+ if (language === "yaml") {
74
+ // YAML line: "key: value" or "- item"
75
+ const yamlKeyMatch = line.match(/^(\s*)([\w.\-/]+)(\s*:\s*)(.*)/);
76
+ if (yamlKeyMatch) {
77
+ const [, indent, key, colon, value] = yamlKeyMatch;
78
+ result += escapeHtml(indent);
79
+ result += `<span style="color:${t.fn}">${escapeHtml(key)}</span>`;
80
+ result += `<span style="color:${t.punct}">${escapeHtml(colon)}</span>`;
81
+ // Value coloring
82
+ if (/^(true|false|null|~)$/i.test(value.trim())) {
83
+ result += `<span style="color:${t.keyword};font-weight:600">${escapeHtml(value)}</span>`;
84
+ } else if (/^\d+(\.\d+)?$/.test(value.trim())) {
85
+ result += `<span style="color:${t.number}">${escapeHtml(value)}</span>`;
86
+ } else if (/^["']/.test(value.trim())) {
87
+ result += `<span style="color:${t.string}">${escapeHtml(value)}</span>`;
88
+ } else {
89
+ result += `<span style="color:${t.fg}">${escapeHtml(value)}</span>`;
90
+ }
91
+ return result || " ";
92
+ }
93
+ const yamlDash = line.match(/^(\s*)(- )(.*)/);
94
+ if (yamlDash) {
95
+ result += escapeHtml(yamlDash[1]);
96
+ result += `<span style="color:${t.punct}">${escapeHtml(yamlDash[2])}</span>`;
97
+ result += `<span style="color:${t.fg}">${escapeHtml(yamlDash[3])}</span>`;
98
+ return result || " ";
99
+ }
100
+ }
101
+ if (language === "json") {
102
+ // JSON: color keys in quotes before colon
103
+ const jsonKeyMatch = line.match(/^(\s*)("(?:[^"\\]|\\.)*")(\s*:\s*)(.*)/);
104
+ if (jsonKeyMatch) {
105
+ const [, indent, key, colon, value] = jsonKeyMatch;
106
+ result += escapeHtml(indent);
107
+ result += `<span style="color:${t.fn}">${escapeHtml(key)}</span>`;
108
+ result += `<span style="color:${t.punct}">${escapeHtml(colon)}</span>`;
109
+ if (/^(true|false|null)/.test(value.trim())) {
110
+ result += `<span style="color:${t.keyword};font-weight:600">${escapeHtml(value)}</span>`;
111
+ } else if (/^\d/.test(value.trim())) {
112
+ result += `<span style="color:${t.number}">${escapeHtml(value)}</span>`;
113
+ } else if (/^"/.test(value.trim())) {
114
+ result += `<span style="color:${t.string}">${escapeHtml(value)}</span>`;
115
+ } else {
116
+ result += `<span style="color:${t.fg}">${escapeHtml(value)}</span>`;
117
+ }
118
+ return result || " ";
119
+ }
120
+ }
121
+ while (i < line.length) {
122
+ // Comments: // or # to end of line
123
+ if (commentChar && line.startsWith(commentChar, i) && (i === 0 || /\s/.test(line[i - 1]) || i === 0)) {
124
+ result += `<span style="color:${t.comment};font-style:italic">${escapeHtml(line.slice(i))}</span>`;
125
+ break;
126
+ }
127
+
128
+ // Strings: single or double quoted
129
+ if (line[i] === '"' || line[i] === "'" || line[i] === "`") {
130
+ const q = line[i];
131
+ let j = i + 1;
132
+ while (j < line.length && line[j] !== q) {
133
+ if (line[j] === "\\") j++;
134
+ j++;
135
+ }
136
+ j = Math.min(j + 1, line.length);
137
+ result += `<span style="color:${t.string}">${escapeHtml(line.slice(i, j))}</span>`;
138
+ i = j;
139
+ continue;
140
+ }
141
+
142
+ // Numbers
143
+ if (/\d/.test(line[i]) && (i === 0 || /[\s,;(=+\-*/<>!&|]/.test(line[i - 1]))) {
144
+ let j = i;
145
+ while (j < line.length && /[\d.]/.test(line[j])) j++;
146
+ result += `<span style="color:${t.number}">${escapeHtml(line.slice(i, j))}</span>`;
147
+ i = j;
148
+ continue;
149
+ }
150
+
151
+ // Words (keywords, identifiers)
152
+ if (/[a-zA-Z_$]/.test(line[i])) {
153
+ let j = i;
154
+ while (j < line.length && /[a-zA-Z0-9_$]/.test(line[j])) j++;
155
+ const word = line.slice(i, j);
156
+ if (keywords.has(word)) {
157
+ result += `<span style="color:${t.keyword};font-weight:600">${escapeHtml(word)}</span>`;
158
+ } else if (j < line.length && line[j] === "(") {
159
+ result += `<span style="color:${t.fn}">${escapeHtml(word)}</span>`;
160
+ } else {
161
+ result += `<span style="color:${t.fg}">${escapeHtml(word)}</span>`;
162
+ }
163
+ i = j;
164
+ continue;
165
+ }
166
+
167
+ // Punctuation / operators
168
+ if (/[{}()\[\];:.,=+\-*/<>!&|?%^~@]/.test(line[i])) {
169
+ result += `<span style="color:${t.punct}">${escapeHtml(line[i])}</span>`;
170
+ i++;
171
+ continue;
172
+ }
173
+
174
+ // Whitespace and anything else
175
+ result += escapeHtml(line[i]);
176
+ i++;
177
+ }
178
+ return result || " ";
179
+ }
180
+ function renderLines(code, theme, language) {
181
+ const lines = code.split("\n");
182
+ return lines.map((line, i) => `<div class="shiki-line" id="line_${i}"><span class="line-num">${i + 1}</span><span class="line-code">${tokenizeLine(line, theme, language)}</span></div>`).join("");
183
+ }
184
+ class CodeClip extends BrowserClip {
185
+ get html() {
186
+ const code = this.attrs.code || "";
187
+ const language = this.attrs.language || "javascript";
188
+ const t = THEMES[this.attrs.theme] || THEMES.dark;
189
+ const linesHtml = renderLines(code, t, language);
190
+ return `<div id="code-container"><pre><code>${linesHtml}</code></pre></div>`;
191
+ }
192
+ get css() {
193
+ const fs = this.attrs.fontSize || 14;
194
+ const t = THEMES[this.attrs.theme] || THEMES.dark;
195
+ return `
196
+ #code-container {
197
+ width: 100%;
198
+ height: 100%;
199
+ display: flex;
200
+ align-items: center;
201
+ justify-content: center;
202
+ padding: 24px;
203
+ box-sizing: border-box;
204
+ background: ${t.bg};
205
+ }
206
+
207
+ pre {
208
+ margin: 0;
209
+ padding: 20px 24px;
210
+ border-radius: 10px;
211
+ background: ${t.bg};
212
+ font-size: ${fs}px;
213
+ line-height: 1.7;
214
+ overflow-x: auto;
215
+ width: 100%;
216
+ max-height: 100%;
217
+ box-sizing: border-box;
218
+ font-family: "Fira Code", "Cascadia Code", "JetBrains Mono", "Consolas", monospace;
219
+ }
220
+
221
+ code {
222
+ color: ${t.fg};
223
+ }
224
+
225
+ .shiki-line {
226
+ display: flex;
227
+ padding: 1px 8px;
228
+ border-radius: 4px;
229
+ gap: 16px;
230
+ }
231
+
232
+ .line-num {
233
+ color: ${t.lineNum};
234
+ user-select: none;
235
+ min-width: 2em;
236
+ text-align: right;
237
+ flex-shrink: 0;
238
+ }
239
+
240
+ .line-code {
241
+ white-space: pre;
242
+ }
243
+ `;
244
+ }
245
+ onAfterRender() {
246
+ this.attrs.code || "";
247
+ const container = this.context.getElements("#code-container")[0];
248
+ const lines = container.querySelectorAll(".shiki-line");
249
+ this.setCustomEntity("code", {
250
+ container,
251
+ lines,
252
+ lineCount: lines.length
253
+ });
254
+ }
255
+ }
256
+
257
+ /**
258
+ * CodeHighlight — Effect that pulses a line's background color.
259
+ *
260
+ * Selector: !#code
261
+ * animatedAttrs: { highlightLine_N: 1 } — where N is the line index (0-based)
262
+ * The line index is parsed from the attr key.
263
+ *
264
+ * Attrs:
265
+ * color: string (default: "rgba(99,102,241,0.25)") — highlight background
266
+ */
267
+ class CodeHighlight extends Effect {
268
+ getScratchValue() {
269
+ return 0;
270
+ }
271
+ onGetContext() {
272
+ this._lines = this.element?.entity?.lines;
273
+ this._color = this.attrs.color || "rgba(99,102,241,0.25)";
274
+ // Parse line index from attributeKey: "highlightLine_4" → 4
275
+ const key = this.attributeKey || "";
276
+ this._lineIndex = parseInt(key.split("_").pop(), 10);
277
+ }
278
+ onProgress(millisecond) {
279
+ if (!this._lines || isNaN(this._lineIndex) || this._lineIndex < 0 || this._lineIndex >= this._lines.length) return;
280
+ const fraction = this.getFraction(millisecond);
281
+ const line = this._lines[this._lineIndex];
282
+
283
+ // Double pump: 0→0.25 up, 0.25→0.5 down, 0.5→0.75 up, 0.75→1 down
284
+ let intensity;
285
+ if (fraction < 0.25) {
286
+ intensity = fraction / 0.25;
287
+ } else if (fraction < 0.5) {
288
+ intensity = 1 - (fraction - 0.25) / 0.25;
289
+ } else if (fraction < 0.75) {
290
+ intensity = (fraction - 0.5) / 0.25;
291
+ } else {
292
+ intensity = 1 - (fraction - 0.75) / 0.25;
293
+ }
294
+ if (intensity > 0.01) {
295
+ const alpha = intensity * 0.35;
296
+ const baseRgb = this._color.match(/\d+/g);
297
+ if (baseRgb && baseRgb.length >= 3) {
298
+ line.style.backgroundColor = `rgba(${baseRgb[0]},${baseRgb[1]},${baseRgb[2]},${alpha})`;
299
+ }
300
+ } else {
301
+ line.style.backgroundColor = "";
302
+ }
303
+ }
304
+ }
305
+
306
+ /**
307
+ * WriteCode — Effect that progressively reveals code lines.
308
+ *
309
+ * Selector: !#code
310
+ * animatedAttrs: { writeCode: 1 } — fraction 0→1 reveals all lines
311
+ */
312
+ class WriteCode extends Effect {
313
+ getScratchValue() {
314
+ return 0;
315
+ }
316
+ onGetContext() {
317
+ this._lines = this.element?.entity?.lines;
318
+ if (this._lines) {
319
+ // Hide all lines initially
320
+ for (const line of this._lines) {
321
+ line.style.opacity = "0";
322
+ }
323
+ }
324
+ }
325
+ onProgress(millisecond) {
326
+ if (!this._lines) return;
327
+ const fraction = this.getFraction(millisecond);
328
+ const initial = this.initialValue ?? 0;
329
+ const target = this.targetValue;
330
+ const current = initial + (target - initial) * fraction;
331
+ const total = this._lines.length;
332
+ const revealUpTo = current * total;
333
+ for (let i = 0; i < total; i++) {
334
+ if (i < Math.floor(revealUpTo)) {
335
+ this._lines[i].style.opacity = "1";
336
+ } else if (i < revealUpTo) {
337
+ this._lines[i].style.opacity = String(revealUpTo - i);
338
+ } else {
339
+ this._lines[i].style.opacity = "0";
340
+ }
341
+ }
342
+ }
343
+ }
344
+
345
+ var name = "@kissmybutton/mc-code";
346
+ var version = "0.0.1";
347
+
348
+ var index = {
349
+ npm_name: name,
350
+ version: version,
351
+ incidents: [{
352
+ exportable: CodeHighlight,
353
+ name: "CodeHighlight"
354
+ }, {
355
+ exportable: WriteCode,
356
+ name: "WriteCode"
357
+ }],
358
+ Clip: {
359
+ exportable: CodeClip
360
+ }
361
+ };
362
+
363
+ export { index as default };
@@ -0,0 +1 @@
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@donkeyclip/motorcortex")):"function"==typeof define&&define.amd?define(["@donkeyclip/motorcortex"],t):(e="undefined"!=typeof globalThis?globalThis:e||self)["@kissmybutton/mc-code"]=t(e.MotorCortex)}(this,(function(e){"use strict";const t={dark:{bg:"#1e1e2e",fg:"#cdd6f4",lineNum:"#585b70",keyword:"#cba6f7",string:"#a6e3a1",comment:"#6c7086",fn:"#89b4fa",number:"#fab387",punct:"#94e2d5",type:"#f9e2af"},light:{bg:"#fafafa",fg:"#383a42",lineNum:"#9ca0b0",keyword:"#a626a4",string:"#50a14f",comment:"#a0a1a7",fn:"#4078f2",number:"#986801",punct:"#0184bc",type:"#c18401"}},n={javascript:new Set(["const","let","var","function","return","if","else","for","while","do","switch","case","break","continue","new","this","class","extends","import","export","default","from","of","in","typeof","instanceof","try","catch","finally","throw","async","await","yield","null","undefined","true","false"]),typescript:new Set(["const","let","var","function","return","if","else","for","while","do","switch","case","break","continue","new","this","class","extends","import","export","default","from","of","in","typeof","instanceof","try","catch","finally","throw","async","await","yield","null","undefined","true","false","type","interface","enum","implements","declare","readonly","as","is","keyof","never","unknown","any","void","abstract","override","satisfies","infer"]),python:new Set(["def","return","if","elif","else","for","while","in","not","and","or","is","class","import","from","as","with","try","except","finally","raise","pass","break","continue","yield","lambda","None","True","False","self","print","range","len","dict","list","set","tuple","int","str","float","bool","async","await"]),bash:new Set(["if","then","else","elif","fi","for","do","done","while","until","case","esac","function","return","in","echo","exit","export","source","local","readonly","declare","set","unset","shift","cd","pwd","ls","grep","sed","awk","cat","mkdir","rm","cp","mv","chmod","chown","sudo","apt","yum","npm","pip","git","docker","kubectl"]),html:new Set(["div","span","p","a","img","ul","ol","li","h1","h2","h3","h4","h5","h6","table","tr","td","th","form","input","button","select","option","textarea","label","header","footer","nav","main","section","article","aside","script","style","link","meta","head","body","html"]),css:new Set(["color","background","border","margin","padding","display","position","width","height","font","text","flex","grid","align","justify","overflow","opacity","transform","transition","animation","z-index","top","left","right","bottom","none","auto","inherit","initial","important"])},s={javascript:"//",typescript:"//",python:"#",bash:"#",yaml:"#",css:null,json:null,html:null};function i(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function o(e,t,o){return e.split("\n").map(((e,a)=>`<div class="shiki-line" id="line_${a}"><span class="line-num">${a+1}</span><span class="line-code">${function(e,t,o){const a=t,l=n[o]||n.javascript,r=s[o]??"//";let c="",p=0;if("yaml"===o){const t=e.match(/^(\s*)([\w.\-/]+)(\s*:\s*)(.*)/);if(t){const[,e,n,s,o]=t;return c+=i(e),c+=`<span style="color:${a.fn}">${i(n)}</span>`,c+=`<span style="color:${a.punct}">${i(s)}</span>`,/^(true|false|null|~)$/i.test(o.trim())?c+=`<span style="color:${a.keyword};font-weight:600">${i(o)}</span>`:/^\d+(\.\d+)?$/.test(o.trim())?c+=`<span style="color:${a.number}">${i(o)}</span>`:/^["']/.test(o.trim())?c+=`<span style="color:${a.string}">${i(o)}</span>`:c+=`<span style="color:${a.fg}">${i(o)}</span>`,c||" "}const n=e.match(/^(\s*)(- )(.*)/);if(n)return c+=i(n[1]),c+=`<span style="color:${a.punct}">${i(n[2])}</span>`,c+=`<span style="color:${a.fg}">${i(n[3])}</span>`,c||" "}if("json"===o){const t=e.match(/^(\s*)("(?:[^"\\]|\\.)*")(\s*:\s*)(.*)/);if(t){const[,e,n,s,o]=t;return c+=i(e),c+=`<span style="color:${a.fn}">${i(n)}</span>`,c+=`<span style="color:${a.punct}">${i(s)}</span>`,/^(true|false|null)/.test(o.trim())?c+=`<span style="color:${a.keyword};font-weight:600">${i(o)}</span>`:/^\d/.test(o.trim())?c+=`<span style="color:${a.number}">${i(o)}</span>`:/^"/.test(o.trim())?c+=`<span style="color:${a.string}">${i(o)}</span>`:c+=`<span style="color:${a.fg}">${i(o)}</span>`,c||" "}}for(;p<e.length;){if(r&&e.startsWith(r,p)&&(0===p||/\s/.test(e[p-1])||0===p)){c+=`<span style="color:${a.comment};font-style:italic">${i(e.slice(p))}</span>`;break}if('"'!==e[p]&&"'"!==e[p]&&"`"!==e[p])if(!/\d/.test(e[p])||0!==p&&!/[\s,;(=+\-*/<>!&|]/.test(e[p-1]))if(/[a-zA-Z_$]/.test(e[p])){let t=p;for(;t<e.length&&/[a-zA-Z0-9_$]/.test(e[t]);)t++;const n=e.slice(p,t);l.has(n)?c+=`<span style="color:${a.keyword};font-weight:600">${i(n)}</span>`:t<e.length&&"("===e[t]?c+=`<span style="color:${a.fn}">${i(n)}</span>`:c+=`<span style="color:${a.fg}">${i(n)}</span>`,p=t}else/[{}()\[\];:.,=+\-*/<>!&|?%^~@]/.test(e[p])?(c+=`<span style="color:${a.punct}">${i(e[p])}</span>`,p++):(c+=i(e[p]),p++);else{let t=p;for(;t<e.length&&/[\d.]/.test(e[t]);)t++;c+=`<span style="color:${a.number}">${i(e.slice(p,t))}</span>`,p=t}else{const t=e[p];let n=p+1;for(;n<e.length&&e[n]!==t;)"\\"===e[n]&&n++,n++;n=Math.min(n+1,e.length),c+=`<span style="color:${a.string}">${i(e.slice(p,n))}</span>`,p=n}}return c||" "}(e,t,o)}</span></div>`)).join("")}class a extends e.BrowserClip{get html(){const e=this.attrs.code||"",n=this.attrs.language||"javascript";return`<div id="code-container"><pre><code>${o(e,t[this.attrs.theme]||t.dark,n)}</code></pre></div>`}get css(){const e=this.attrs.fontSize||14,n=t[this.attrs.theme]||t.dark;return`\n #code-container {\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n box-sizing: border-box;\n background: ${n.bg};\n }\n\n pre {\n margin: 0;\n padding: 20px 24px;\n border-radius: 10px;\n background: ${n.bg};\n font-size: ${e}px;\n line-height: 1.7;\n overflow-x: auto;\n width: 100%;\n max-height: 100%;\n box-sizing: border-box;\n font-family: "Fira Code", "Cascadia Code", "JetBrains Mono", "Consolas", monospace;\n }\n\n code {\n color: ${n.fg};\n }\n\n .shiki-line {\n display: flex;\n padding: 1px 8px;\n border-radius: 4px;\n gap: 16px;\n }\n\n .line-num {\n color: ${n.lineNum};\n user-select: none;\n min-width: 2em;\n text-align: right;\n flex-shrink: 0;\n }\n\n .line-code {\n white-space: pre;\n }\n `}onAfterRender(){this.attrs.code;const e=this.context.getElements("#code-container")[0],t=e.querySelectorAll(".shiki-line");this.setCustomEntity("code",{container:e,lines:t,lineCount:t.length})}}class l extends e.Effect{getScratchValue(){return 0}onGetContext(){this._lines=this.element?.entity?.lines,this._color=this.attrs.color||"rgba(99,102,241,0.25)";const e=this.attributeKey||"";this._lineIndex=parseInt(e.split("_").pop(),10)}onProgress(e){if(!this._lines||isNaN(this._lineIndex)||this._lineIndex<0||this._lineIndex>=this._lines.length)return;const t=this.getFraction(e),n=this._lines[this._lineIndex];let s;if(s=t<.25?t/.25:t<.5?1-(t-.25)/.25:t<.75?(t-.5)/.25:1-(t-.75)/.25,s>.01){const e=.35*s,t=this._color.match(/\d+/g);t&&t.length>=3&&(n.style.backgroundColor=`rgba(${t[0]},${t[1]},${t[2]},${e})`)}else n.style.backgroundColor=""}}class r extends e.Effect{getScratchValue(){return 0}onGetContext(){if(this._lines=this.element?.entity?.lines,this._lines)for(const e of this._lines)e.style.opacity="0"}onProgress(e){if(!this._lines)return;const t=this.getFraction(e),n=this.initialValue??0,s=n+(this.targetValue-n)*t,i=this._lines.length,o=s*i;for(let e=0;e<i;e++)e<Math.floor(o)?this._lines[e].style.opacity="1":this._lines[e].style.opacity=e<o?String(o-e):"0"}}return{npm_name:"@kissmybutton/mc-code",version:"0.0.1",incidents:[{exportable:l,name:"CodeHighlight"},{exportable:r,name:"WriteCode"}],Clip:{exportable:a}}}));
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@kissmybutton/mc-code",
3
+ "version": "0.0.1",
4
+ "description": "MotorCortex code display plugin — Shiki syntax highlighting with line-level animation",
5
+ "main": "dist/bundle.cjs.js",
6
+ "module": "dist/bundle.esm.js",
7
+ "browser": "dist/bundle.umd.js",
8
+ "type": "module",
9
+ "author": "Donkeyclip",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/kissmybutton/mc-code.git"
13
+ },
14
+ "license": "MIT",
15
+ "engines": {
16
+ "node": ">=16"
17
+ },
18
+ "scripts": {
19
+ "lint": "eslint -c .eslintrc src/**/*.js",
20
+ "lint:fix": "npm run lint -- --fix",
21
+ "build": "npm run build:lib && npm run build:demo",
22
+ "build:lib": "rollup -c",
23
+ "start": "npm run build:lib && concurrently -c \"cyan.bold,magenta.bold\" \"npm:build:lib -- -w\" \"npm:start:demo\" ",
24
+ "start:demo": "webpack serve --mode=development --config ./demo/webpack.config.cjs",
25
+ "build:demo": "webpack --mode=production --config ./demo/webpack.config.cjs",
26
+ "test": "echo \"No tests yet\"",
27
+ "test:prod": "npm run lint",
28
+ "prepare": "husky install"
29
+ },
30
+ "keywords": [
31
+ "motorcortex",
32
+ "code",
33
+ "shiki",
34
+ "syntax-highlighting"
35
+ ],
36
+ "lint-staged": {
37
+ "*.{json,md,yml,yaml,css}": [
38
+ "prettier --write"
39
+ ],
40
+ "*.{js,jsx}": [
41
+ "prettier --write",
42
+ "eslint --fix"
43
+ ]
44
+ },
45
+ "peerDependencies": {
46
+ "@donkeyclip/motorcortex": ">=9.24.0"
47
+ },
48
+ "devDependencies": {
49
+ "@babel/cli": "^7.23.4",
50
+ "@babel/core": "^7.23.3",
51
+ "@babel/eslint-parser": "^7.23.3",
52
+ "@babel/plugin-syntax-import-assertions": "^7.23.3",
53
+ "@babel/plugin-syntax-jsx": "^7.23.3",
54
+ "@babel/plugin-transform-react-jsx": "^7.22.15",
55
+ "@babel/preset-env": "^7.23.3",
56
+ "@babel/preset-react": "^7.23.3",
57
+ "@donkeyclip/motorcortex": "^9.24.0",
58
+ "@donkeyclip/motorcortex-player": "^2.15.18",
59
+ "@rollup/plugin-babel": "6.0.4",
60
+ "@rollup/plugin-commonjs": "25.0.8",
61
+ "@rollup/plugin-json": "6.1.0",
62
+ "@rollup/plugin-node-resolve": "^15.2.3",
63
+ "babel-loader": "9.2.1",
64
+ "concurrently": "^9.0.0",
65
+ "core-js": "^3.33.3",
66
+ "css-loader": "6.11.0",
67
+ "eslint": "^8.54.0",
68
+ "eslint-config-prettier": "9.1.0",
69
+ "eslint-plugin-babel": "5.3.1",
70
+ "eslint-plugin-import": "^2.29.0",
71
+ "eslint-plugin-node": "11.1.0",
72
+ "eslint-plugin-prettier": "5.2.1",
73
+ "eslint-plugin-promise": "6.6.0",
74
+ "eslint-plugin-react": "^7.33.2",
75
+ "husky": "8.0.3",
76
+ "prettier": "3.4.2",
77
+ "rimraf": "5.0.10",
78
+ "rollup": "4.28.1",
79
+ "webpack": "^5.89.0",
80
+ "webpack-cli": "5.1.4",
81
+ "webpack-dev-server": "4.15.2"
82
+ },
83
+ "dependencies": {
84
+ "@rollup/plugin-terser": "^0.4.4",
85
+ "shiki": "^3.0.0"
86
+ }
87
+ }
package/renovate.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": [
3
+ "config:base",
4
+ ":separateMajorReleases",
5
+ ":automergeMinor",
6
+ ":disablePeerDependencies",
7
+ ":semanticCommits",
8
+ ":automergeBranch"
9
+ ]
10
+ }
@@ -0,0 +1,67 @@
1
+ import babel from "@rollup/plugin-babel";
2
+ import commonjs from "@rollup/plugin-commonjs";
3
+ import json from "@rollup/plugin-json";
4
+ import resolve from "@rollup/plugin-node-resolve";
5
+ import terser from "@rollup/plugin-terser";
6
+ import pkg from "./package.json" with { type: "json" };
7
+
8
+ export default [
9
+ {
10
+ input: "src/index.js",
11
+ external: ["@donkeyclip/motorcortex"],
12
+ output: [
13
+ { file: pkg.main, format: "cjs", inlineDynamicImports: true },
14
+ { file: pkg.module, format: "es", inlineDynamicImports: true },
15
+ ],
16
+ plugins: [
17
+ resolve(),
18
+ babel({
19
+ plugins: [
20
+ "@babel/plugin-syntax-jsx",
21
+ [
22
+ "@babel/plugin-transform-react-jsx",
23
+ {
24
+ pragma: "JSX",
25
+ },
26
+ ],
27
+ ],
28
+ extensions: [".js", ".jsx"],
29
+ }),
30
+ commonjs(),
31
+ json(),
32
+ ],
33
+ },
34
+ {
35
+ input: "src/index.js",
36
+ external: ["@donkeyclip/motorcortex"],
37
+ output: [
38
+ {
39
+ globals: {
40
+ "@donkeyclip/motorcortex": "MotorCortex",
41
+ },
42
+ name: pkg.name,
43
+ file: pkg.browser,
44
+ format: "umd",
45
+ inlineDynamicImports: true,
46
+ },
47
+ ],
48
+ plugins: [
49
+ json(),
50
+ resolve({ mainFields: ["module", "main", "browser"] }),
51
+ babel({
52
+ plugins: [
53
+ "@babel/plugin-syntax-jsx",
54
+ [
55
+ "@babel/plugin-transform-react-jsx",
56
+ {
57
+ pragma: "JSX",
58
+ },
59
+ ],
60
+ ],
61
+ extensions: [".js", ".jsx"],
62
+ }),
63
+ commonjs(),
64
+ terser(),
65
+ ],
66
+ },
67
+ ];