cursor-aura 0.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.
@@ -0,0 +1,56 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ export { Aura as AuraVanilla } from './vanilla/index.cjs';
3
+
4
+ interface AuraProps {
5
+ /**
6
+ * The shadow color for the cursor.
7
+ * Accepts any valid CSS color: hex, rgb, hsl, or CSS variable.
8
+ * @default '#000'
9
+ */
10
+ color?: string;
11
+ }
12
+ /**
13
+ * Aura - Themed cursor shadows for the web
14
+ *
15
+ * Renders a hidden marker element to detect the correct document context
16
+ * (portal-proof). Applies custom cursors via CSS custom properties on the
17
+ * document root. The shadow color updates automatically when the
18
+ * color prop changes.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <Aura color="#0C3EFF" />
23
+ * <Aura color="var(--theme-color)" />
24
+ * ```
25
+ */
26
+ declare function Aura({ color }: AuraProps): react_jsx_runtime.JSX.Element;
27
+
28
+ type CursorType = 'default' | 'pointer' | 'grab' | 'grabbing' | 'text';
29
+ /**
30
+ * Generates an SVG cursor with a colored shadow baked in
31
+ * Uses variable scale per cursor type (default: 1.7x, others: 1.5x)
32
+ * @param type - The cursor type
33
+ * @param shadowColor - The shadow color
34
+ * @param pressed - When true, uses smaller shadow offset for "pressed" feel
35
+ */
36
+ declare function generateCursorSVG(type: CursorType, shadowColor: string, pressed?: boolean): string;
37
+ /**
38
+ * Converts SVG string to a data URI for use in CSS cursor property
39
+ */
40
+ declare function toDataURI(svg: string): string;
41
+ /**
42
+ * Generates all cursor data URIs using the provided shadow color
43
+ * Results are cached for performance
44
+ * @param pressed - When true, generates cursors with smaller shadow offset
45
+ */
46
+ declare function generateThemedCursors(shadowColor: string, pressed?: boolean): Record<CursorType, string>;
47
+ /**
48
+ * Returns the CSS cursor value with hotspot coordinates
49
+ */
50
+ declare function getCursorCSS(dataURI: string, type: CursorType, fallback: string): string;
51
+ /**
52
+ * Clears the cursor cache
53
+ */
54
+ declare function clearCursorCache(): void;
55
+
56
+ export { Aura, type AuraProps, type CursorType, clearCursorCache, Aura as default, generateCursorSVG, generateThemedCursors, getCursorCSS, toDataURI };
@@ -0,0 +1,56 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ export { Aura as AuraVanilla } from './vanilla/index.js';
3
+
4
+ interface AuraProps {
5
+ /**
6
+ * The shadow color for the cursor.
7
+ * Accepts any valid CSS color: hex, rgb, hsl, or CSS variable.
8
+ * @default '#000'
9
+ */
10
+ color?: string;
11
+ }
12
+ /**
13
+ * Aura - Themed cursor shadows for the web
14
+ *
15
+ * Renders a hidden marker element to detect the correct document context
16
+ * (portal-proof). Applies custom cursors via CSS custom properties on the
17
+ * document root. The shadow color updates automatically when the
18
+ * color prop changes.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <Aura color="#0C3EFF" />
23
+ * <Aura color="var(--theme-color)" />
24
+ * ```
25
+ */
26
+ declare function Aura({ color }: AuraProps): react_jsx_runtime.JSX.Element;
27
+
28
+ type CursorType = 'default' | 'pointer' | 'grab' | 'grabbing' | 'text';
29
+ /**
30
+ * Generates an SVG cursor with a colored shadow baked in
31
+ * Uses variable scale per cursor type (default: 1.7x, others: 1.5x)
32
+ * @param type - The cursor type
33
+ * @param shadowColor - The shadow color
34
+ * @param pressed - When true, uses smaller shadow offset for "pressed" feel
35
+ */
36
+ declare function generateCursorSVG(type: CursorType, shadowColor: string, pressed?: boolean): string;
37
+ /**
38
+ * Converts SVG string to a data URI for use in CSS cursor property
39
+ */
40
+ declare function toDataURI(svg: string): string;
41
+ /**
42
+ * Generates all cursor data URIs using the provided shadow color
43
+ * Results are cached for performance
44
+ * @param pressed - When true, generates cursors with smaller shadow offset
45
+ */
46
+ declare function generateThemedCursors(shadowColor: string, pressed?: boolean): Record<CursorType, string>;
47
+ /**
48
+ * Returns the CSS cursor value with hotspot coordinates
49
+ */
50
+ declare function getCursorCSS(dataURI: string, type: CursorType, fallback: string): string;
51
+ /**
52
+ * Clears the cursor cache
53
+ */
54
+ declare function clearCursorCache(): void;
55
+
56
+ export { Aura, type AuraProps, type CursorType, clearCursorCache, Aura as default, generateCursorSVG, generateThemedCursors, getCursorCSS, toDataURI };
package/dist/index.js ADDED
@@ -0,0 +1,345 @@
1
+ import { useRef, useLayoutEffect, useEffect } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ // src/react/Aura.tsx
5
+
6
+ // src/core/cursors.ts
7
+ var CURSOR_SCALES = {
8
+ default: 1.7,
9
+ pointer: 1.5,
10
+ grab: 1.5,
11
+ grabbing: 1.5,
12
+ text: 1.3
13
+ };
14
+ var CURSOR_PATHS = {
15
+ default: {
16
+ viewBox: "0 0 32 32",
17
+ translate: [10, 7],
18
+ // From mac-cursors/default.svg
19
+ hotspot: [10, 7],
20
+ // Arrow tip at origin, so hotspot = translate
21
+ // From mac-cursors/default.svg - white is background stroke, main is black fill
22
+ main: "m6.431 17 1.765-.941-2.775-5.202h3.604l-8.025-8.043v11.188l2.53-2.442z",
23
+ highlight: "m6.148 18.473 1.863-1.003 1.615-.839-2.568-4.816h4.332l-11.379-11.408v16.015l3.316-3.221z"
24
+ },
25
+ pointer: {
26
+ viewBox: "0 0 32 32",
27
+ translate: [9, 8],
28
+ // From mac-cursors/handpointing.svg
29
+ hotspot: [9, 4],
30
+ // Fingertip ~4px above translate
31
+ main: "m3.8852309 13.5522788c.15029277.1354048.25406355.2326609.57471053.5372549.31406586.2983172.46594413.439273.60482646.5572091.05791893.0487853.10729946.1792495.12686364.3731628.01609788.1595565.01049553.3375341-.0090192.5090254-.00674888.0593077-.01325791.1020883-.01698742.1224696-.04186639.2287942.13249226.4401222.36507344.4424801.20929712.0021219.37056581.00472.79741331.0123273.10679864.0019014.10679864.0019014.21395196.0037648 1.16029156.0199598 1.75290683.01448 2.1782236-.039003.45462139-.05716.92282087-.6061887 1.32754658-1.2951218.3429437.6096032.818651 1.2048784 1.2990136 1.282277.1525992.0243739.3372104.0319365.5511764.0270146.1595258-.0036697.328349-.0141847.4987188-.0294071.1284742-.0114791.2308379-.0230173.2919821-.0309462.2259121-.0292954.3737346-.2515956.31337-.4712558-.0130388-.0474468-.0339905-.1345046-.0551176-.2441066-.0244927-.1270617-.0421932-.2511642-.0502379-.3642189-.0051002-.0716765-.0061057-.1365707-.0028638-.1926702.0056365-.097781.007395-.1525378.0101327-.2790463.0010457-.0470941.0010457-.0470941.0024433-.0883088.0052898-.134881.0234093-.2629524.0820463-.5422232.0251901-.1212103.1472903-.3531692.3395862-.6402332.0572734-.0854992.1198813-.1747825.1869659-.2669588.127207-.1747861.2641214-.3514011.4010853-.5204043.0820457-.1012383.1454717-.1769623.1807968-.2180763.2962199-.424403.6120842-1.1191696.7281396-1.5253635.111416-.3904017.2005405-1.10937558.2553074-1.81604479.0300143-.40088807.0411211-.72405394.0411211-1.23097561.0000507-.08891816.0000507-.08891816.0002032-.16234685.0002858-.12025251.0003032-.16573976-.0000887-.22195195-.0010706-.15358041-.0055478-.30580145-.0203882-.6940256-.0319191-.81365149-.4778003-1.3396911-1.1348711-1.44115781-.5589865-.08632026-1.2393839.37795756-1.2393839.37795756s-.1514404-.5228127-.2537197-.6842075c-.1661957-.25934741-.5941748-.58982828-.9213451-.65421118-.3365014-.0653413-.7354024-.05811592-1.1017193.00667481-.3207944.05740454-.64034865.34382687-.82518751.65277182-.13223727.22039488-.00786932-.01169164-.14013104-.2396787-.1830552-.31402315-.60932935-.59522407-1.01524567-.67822294-.34396352-.07112559-.73801897-.04403625-1.09795562.06293793-.46304125.13836397-.53675291.49073282-.55516748.38984626-.06158674-.3382385-.06727482-.3160095-.105656-.55729603-.14258072-.89527436-.30213161-1.51473549-.54406219-2.05528331.01391678.0310773-.08860981-.20214701-.12592279-.28256779-.06461002-.13925416-.12910532-.2652956-.19999629-.38652204-.21850342-.37364978-.46891278-.65340904-.7830908-.81233894-.54561037-.27629378-1.3634177-.14183064-1.75105565.31064856-.38495968.44966797-.4491432 1.20149287-.3521966 2.13184003.03702376.36121263.16678627 1.02066144.28444961 1.50812387.04160602.1691894.07805979.32348903.14491578.60851331.01149723.04848415.01149723.04848415.02309483.09698036.05172236.21571896.09707607.39320067.15122332.5879629-.00568154-.02030261.09701461.344086.11888835.42472961.00727686.02691587.00727686.02691587.01448296.05395339.04082856.15377935.08074083.31959314.14309954.5963099.03412572.1521447.06742545.31468601.09999775.48699018.08883553.46993091.089274.37207374.00375852.27186198-.05907319-.06922522-.11463055-.13209255-.16830659-.19003644-.09976937-.10770214-.19148509-.19677225-.2785569-.2678141-.6343975-.51905295-1.02312991-.74839425-1.55681885-.79878106-.87541567-.08410158-1.70619803.53426712-1.83111632 1.36882761-.07682697.51169638-.05207639.74723271.18463583 1.19942735.13026223.24432805.35060714.53942202.76172732 1.04735429.02515953.031068.02515953.031068.05030428.06206416.50464537.62186746.55962098.69095396.67961467.86473786.32435479.4706845 1.1139501 1.8221455 1.25748612 2.0035872z",
32
+ highlight: "m1.68266944 9.2716401c-.02488625-.03067752-.02488625-.03067752-.04970567-.06132555-.37729166-.46613768-.58418002-.74321015-.68156241-.9258495-.15281729-.29195235-.1611316-.37107459-.10605794-.73788601.06473349-.43247455.53181583-.78013371 1.01829549-.73339767.33660502.03178017.63068475.20527903 1.15339692.63295262.0565942.04617564.12482853.1124417.20288232.19670163.04616569.04983637.09513192.10524534.14800114.16720042.0794093.0930562.34702847.42052231.30761424.37286894.05814283.06991619.09971852.12407704.14721655.19045018.0941062.13434104.14705111.20894642.21874992.30454484-.0336171-.04487143.21473082.29843305.26732159.34863333.27859812.26593456.68203289.04195871.65675979-.31244785-.00421914-.05916537-.01812774-.12308431-.04717934-.23466885-.11487425-.81923739-.15505751-1.08218312-.24678252-1.56739907-.03407352-.18024544-.06905328-.35098727-.10521102-.5121905-.06435409-.28557213-.10635725-.46007245-.14994794-.62425526-.00774801-.02907063-.00774801-.02907063-.01552357-.05783095-.02300644-.08481964-.12725123-.45470311-.12030828-.42989063-.05134381-.18468043-.0945453-.35373996-.14431997-.56133562-.01130896-.04728909-.01130896-.04728909-.02259904-.09489949-.06649254-.28350912-.10387999-.44176072-.14606063-.6132721-.10998732-.45567652-.23425389-1.08719519-.2671036-1.40768017-.07546665-.72422018-.02339381-1.33418457.17582284-1.56688778.15554834-.1815673.59641015-.25405339.84271752-.12932486.16107512.0814814.32204278.26131571.47435101.521769.05764302.09857191.11172763.20426801.16708381.32357735.0335256.07225783.13292567.29837003.12172905.27336705.21032209.46992469.354801 1.03086841.48791736 1.86671535.03939531.24766201.08813662.52823537.15063928.87150416.01857903.10178746.01857903.10178746.03722922.20314381.30139226 1.63533599.27933797 1.51139381.28367122 1.64182468.01580667.47578071.71810567.4869267.74900255.01188722.00979855-.15065269.00630989-.2851661-.01107827-.67146517-.00245496-.05465243-.00245496-.05465243-.00481877-.10910149-.01521525-.35590459-.01433687-.56066672.00670546-.67705709.03834708-.21223125.22887-.4499778.40434754-.50241339.24641865-.07323589.51640341-.09179599.73269877-.04707051.20703808.0423346.44864736.20171736.51796318.32062499.08353628.14399789.15516008.36337367.21006107.63530456.04431149.21947986.07480439.45493493.0962536.70624261.00667352.0781897.01103024.13859819.01772256.23854675.00285005.04183594.00285005.04183594.00568968.07635213.00160285.01731471.00160285.01731471.00551199.04467336.00303535.01917374.00303535.01917374.01734216.06773608.00727602.13782339.00727602.13782339.56081544.18893151.16530264-.19982737.16530264-.19982737.16077268-.23486454.02708074-.1183491.04365279-.250265.06727822-.49813693.01508098-.16112409.02268576-.24033521.03157416-.32249887.036794-.34012028.0835164-.55621578.140511-.65120691.0707148-.11819408.3197845-.28280909.4314962-.30279961.2805348-.04961763.5886064-.0551978.8264635-.00901194.1077347.021202.3705429.22413969.4327499.32121002.1277282.20156171.2519621.8513817.3219188 1.49611734-.0110122.04228902-.0110122.04228902.1607163.28760404.5903408-.06730286.5903408-.06730286.5737568-.17389206.0155734-.03799147.0279666-.08191522.0455068-.15013809.0421947-.1597068.0701719-.25243998.1118273-.35635899.0288165-.07188915.0591935-.13335501.0903398-.18227881.120675-.18992919.4330876-.31896311.7070596-.2766556.2942545.0454396.4817569.26665023.4998934.72896761.0145423.38042999.0188438.52667972.0198445.67022961.0003693.0529684.0003531.09548963.0000723.21509672-.0001536.07391241-.0001536.07391241-.000205.16397385 0 .48892448-.010469.79353263-.0389535 1.17400348-.0506294.653266-.1361064 1.34281542-.228649 1.66708482-.094456.330596-.3764591.9508823-.5997469 1.2734975-.0158389.0153017-.0838055.0964468-.1706932.2036597-.1445918.1784155-.2892331.364998-.4248114.5512865-.0725632.099704-.140705.1968792-.2036767.2908847-.2436695.3637558-.4000227.6607868-.4506249.9042828-.0664376.3164194-.0901813.4842425-.0973169.666189-.0017426.0515155-.0017426.0515155-.0028439.1014735-.0025547.1180556-.0040857.165727-.0090621.2520573-.0052398.0906702-.0037444.1871795.0035093.2891187.0103883.145992.0000001.3454812.0000001.3454812s-.1266332-.0118299-.2678551-.0085813c-.1725177.0039685-.3159859-.0019087-.4151297-.0177442-.143046-.0230487-.5293508-.5064503-.7271506-.8830611-.3022704-.5764228-1.03604858-.5484427-1.33684295-.0394061-.27130191.4618137-.65965243.9172085-.77493336.9317029-.37460536.047106-.95471158.0524702-2.07175566.0332544-.10679478-.0018572-.10679478-.0018572-.21348729-.0037567-.42889761-.0076439-.41241496.0647655-.40363307-.0124079.02506967-.2203068.02222332-.1790312.00000011-.3992999-.03726222-.36933-.15125405-.6704984-.38877094-.8705429-.12286946-.1043424-.26983033-.2407345-.56500741-.5211097-.33722428-.3203411-.44283686-.4193233-.57299128-.5337266l-.80130455-.8907189c-.08795856-.1124788-.86002339-1.4339349-1.21248613-1.9454077-.13710846-.19857111-.18839645-.26302343-.71461353-.9114734zm9.50873056.0037599v3.459c0 .5.75.5.75 0v-3.459c0-.5-.75-.5-.75 0zm-2.03159602-.00057241.016 3.47300001c.00230346.4999947.7522955.4965395.74999204-.0034552l-.016-3.47299999c-.00230346-.4999947-.7522955-.49653951-.74999204.00345518zm-1.20911102 3.45357381-.021-3.42599996c-.00306475-.4999906-.75305066-.49539349-.74998592.00459712l.021 3.42600004c.00306475.4999906.75305066.4953935.74998592-.0045972z"
33
+ },
34
+ grab: {
35
+ viewBox: "0 0 32 32",
36
+ translate: [7, 6],
37
+ // From mac-cursors/handopen.svg
38
+ hotspot: [11, 9],
39
+ // Center of palm area
40
+ // Hand open cursor uses white fill + black stroke structure
41
+ main: "m4.5557 8.5742c-.098-.375-.196-.847-.406-1.552-.167-.557-.342-.859-.47-1.233-.155-.455-.303-.721-.496-1.181-.139-.329-.364-1.048-.457-1.44-.119-.509.033-.924.244-1.206.253-.339.962-.49 1.357-.351.371.13.744.512.916.788.288.46.357.632.717 1.542.393.992.564 1.918.611 2.231l.085.452c-.001-.04-.043-1.122-.044-1.162-.035-1.029-.06-1.823-.038-2.939.002-.126.064-.587.084-.715.078-.5.305-.8.673-.979.412-.201.926-.215 1.401-.017.423.173.626.55.687 1.022.014.109.094.987.093 1.107-.013 1.025.006 1.641.015 2.174.004.231.003 1.625.017 1.469.061-.656.094-3.189.344-3.942.144-.433.405-.746.794-.929.431-.203 1.113-.07 1.404.243.285.305.446.692.482 1.153.032.405-.019.897-.02 1.245 0 .867-.021 1.324-.037 2.121-.001.038-.015.298.023.182.094-.28.188-.542.266-.745.049-.125.241-.614.359-.859.114-.234.211-.369.415-.688.2-.313.415-.448.668-.561.54-.235 1.109.112 1.301.591.086.215.009.713-.028 1.105-.061.647-.254 1.306-.352 1.648-.128.447-.274 1.235-.34 1.601-.072.394-.234 1.382-.359 1.82-.086.301-.371.978-.652 1.384 0 0-1.074 1.25-1.192 1.812-.117.563-.078.567-.101.965-.024.399.121.923.121.923s-.802.104-1.234.034c-.391-.062-.875-.841-1-1.078-.172-.328-.539-.265-.682-.023-.225.383-.709 1.07-1.051 1.113-.668.084-2.054.03-3.139.02 0 0 .185-1.011-.227-1.358-.305-.26-.83-.784-1.144-1.06l-.832-.921c-.284-.36-.629-1.093-1.243-1.985-.348-.504-1.027-1.085-1.284-1.579-.223-.425-.331-.954-.19-1.325.225-.594.675-.897 1.362-.832.519.05.848.206 1.238.537.225.19.573.534.75.748.163.195.203.276.377.509.23.307.302.459.214.121",
42
+ highlight: "",
43
+ // Grab uses stroke-based rendering, not highlight fill
44
+ // Additional finger line paths for grab cursor
45
+ fingerLines: [
46
+ "m11.566 12.734v-3.459",
47
+ "m9.551 12.746-.016-3.473",
48
+ "m7.555 9.305.021 3.426"
49
+ ]
50
+ },
51
+ grabbing: {
52
+ viewBox: "0 0 32 32",
53
+ translate: [8, 9],
54
+ // From mac-cursors/handgrabbing.svg
55
+ hotspot: [12, 14],
56
+ // Center of closed palm
57
+ main: "m3.44281398 1.68449726c-.74326136.27630142-1.05584685.8131257-1.07636853 1.38003696-.01344897.37336893.06665513.72649286.23114214 1.18694303-.02596219-.07267623.09676488.29282004.12116236.37362273.05052942.16918921-.4865367-.05865774-.81377307.00741883-.36363321.07113868-.84783757.38332307-1.10006887.79754775-.29643467.48542737-.3109609 1.04368567-.08235979 2.04824266.12491868.54736183.36572145 1.00836814.71076689 1.44594879.15329951.1944118.5713628.64726015.60307236.6875974l.84854343.94062339c.15080214.1358526.25794954.2361946.57590427.5380259.3147558.2987762.4647038.4380078.60308951.555976.05846214.0492474.10784267.1797116.12740685.3736249.01609788.1595565.01049553.3375341-.0090192.5090254-.00674888.0593077-.01325791.1020883-.01698742.1224696-.04189161.228932.13269563.4403386.36541902.4424835.21585671.0019894.38528595.0046546.82216479.0123538.09483476.0016698.09483476.0016698.18993053.0033129 1.16876447.0200186 1.75308289.0147904 2.17807912-.0385723.45429894-.0572869.92650915-.6110188 1.32698393-1.2957591.34289141.6108338.81859723 1.2057867 1.2995685 1.2820532.1510118.0244148.3353555.0322555.548787.0275887.1606725-.0035131.3307029-.0140241.5021961-.0293376.1276907-.0114022.2293359-.0228648.29003-.0307451.2258836-.0293282.373669-.251611.3133108-.4712481-.0130351-.0474332-.0339838-.1345011-.0551094-.2441635-.0245945-.1276687-.0423383-.2523857-.0503381-.365988-.0050217-.0713101-.0059948-.1359317-.0027687-.1918983.0059157-.0980798.0077938-.1530073.0108033-.281125.0010795-.0448938.0010795-.0448938.0024606-.0845172.0054208-.1364475.0233824-.2649146.0815132-.544638.0250088-.1201275.1473169-.352189.3398902-.639435.0571394-.0852302.1195783-.1742239.1864664-.26609712.1272143-.17473362.2641361-.35131772.4011075-.52030772.082051-.10123129.145482-.17695689.1808122-.21807676.2967593-.42378347.612817-1.11823437.7291396-1.52536348.1117407-.39153936.202351-1.12501196.254373-1.81690429.029923-.39968605.0410555-.72381216.0410555-1.23011613.0000742-.09758414.0000742-.09758414.0002975-.17670236.0003569-.11115478.0003569-.11115478.000115-.20711835-.0008934-.15683883-.0055282-.31323355-.0207085-.69507578-.0313109-.81293139-.4771727-1.33911388-1.1344906-1.44058831-.559108-.08631314-1.0586051.08188477-1.2779293.31625977-.0755526.08073733.0036753-.2781823-.2159489-.62316278-.1644465-.25841586-.593184-.58905957-.9209287-.65355552-.335487-.06535532-.73539548-.05811715-1.1017193.00667481-.32093157.05742909-.68608434.33741751-.87176225.64688068-.12411885.20686477.03884667-.00592296-.09368743-.23401341-.18231052-.31422641-.60754287-.59486422-1.01411454-.67799709-.34643562-.07139428-.74182572-.04452925-1.09945614.0633873-.43336319.1291117-1.01795827.61460976-.94899189 1.15552627-.34375-.54091651-1.25026717-.691379-1.97906097-.42111797z",
58
+ highlight: "m7.31951013 1.62138197c.20710357.04234751.44724204.20083012.51632974.31990811.08404358.1446387.15562749.36413806.21048667.6366124.02933373.14569467.12179446 1.2125285.29383112 1.32370243.41279229.04533731.41279229.04533731.52658055-.12364345.03545705-.07383858.03545705-.07383858.04226523-.1029106.01416796-.06009544.02463332-.12677987.0351322-.21754028l.00854738-.07915386.00047673-.00942804.00327525-.03167185c.01085148-.11424313.04184125-.4312127.05388392-.53034902.03788792-.31189663.08766449-.52757784.13944093-.6138719.0713024-.11883734.31942298-.28274442.43149612-.30279961.2804398-.04960082.58940103-.05519288.82623993-.00905543.1084394.02134018.3709471.22378689.432331.32024744.1291079.20279957.2524316.84889766.3225486 1.4970065-.0102194.04624251-.0102194.04624251.1640069.28984194.5843296-.06677889.5843296-.06677889.5703629-.17490247.0159511-.03856429.0284824-.08294031.045969-.15118961.0423876-.16089067.0697594-.25204451.111066-.35549917.0288558-.07227096.0592914-.13391873.0904889-.18278042.1209187-.19031132.4335712-.319392.7077174-.27707028.2943447.04543991.4816904.26653537.4994912.72869815.0148821.37434892.0193146.5239164.0201469.6700184l-.0004247.37954865c0 .48831141-.0104951.79388164-.0389535 1.17400348-.0480918.63962116-.1348512 1.34192123-.227649 1.66708484-.0946325.33121345-.3766371.95084197-.6003915 1.27298482-.0161892.01580846-.0841508.09694273-.1710333.20413492-.1445842.17838247-.2892181.36491271-.4247891.5511244-.0723398.09936149-.1402862.19620479-.2030964.2898938-.2440054.36396314-.400553.66098894-.4512157.90434304-.0659304.3172546-.0893838.4850003-.0966379.6675968-.0017072.0490782-.0017072.0490782-.002845.096677-.0028064.119476-.004437.1671639-.0097087.2545848-.0052654.091322-.0038193.187354.00332.2887353.0103318.1467182.1058713.3478531.1058713.3478531s-.2321503-.0119819-.3742084-.0088758c-.1718098.0037567-.3147843-.0023244-.4138162-.0183342-.1440353-.0228411-.53014068-.5057331-.7278511-.8821737-.30227042-.5764228-1.03604858-.5484427-1.33684295-.0394061-.26854779.4591613-.65918083.9172326-.7740684.9317199-.37404082.0469647-.94643778.0520862-2.07160079.0328144-.09480875-.0016381-.46003446-.0128683-.64600494-.0157445-.18597048-.0028763.05008807-.1790283.02786486-.399297-.03726222-.36933-.15125405-.6704984-.38877094-.8705429-.12241569-.1043631-.26774964-.2393104-.56509654-.5215613-.33323493-.3163366-.44236499-.4185353-.57290215-.533275l-.80130455-.89071892c-.03955779-.05174211-.45812831-.5051399-.5872217-.6688539-.28069963-.35597842-.47062947-.71959073-.56844755-1.14820437-.18921973-.83150113-.1793328-1.21146622-.00855589-1.49112273.13743587-.2257023.43815377-.4195862.60596039-.45241793.17165981-.03465512.55153059-.01648617.62179422.02229321.09902279.05401056.13357243.07300285.16379074.09097645.03572494.02124891.05965747.03799198.08182912.05708809.03426437.02951139.07235014.07170412.12420211.14044502.03611591.04821025.07806642.1053997.1423779.19304882.06054643.0816627.09183576.12069421.13369221.1590035.28038907.25662728.68391532.03238058.65052057-.32606956-.00567036-.06086415-.02203766-.12694598-.05458621-.23708502-.04356824-.15021272.00433013-.05284275-.26002629-.56642281-.08720664-.16942124-.13955864-.28835362-.17428227-.4046158l-.03412852-.10219113c-.03838756-.11059767-.09558223-.26854489-.12612861-.35199347l-.02009957-.05467087.002.008-.05974804-.17751191c-.09232236-.28807194-.13413567-.51358087-.12645475-.72681781.01040781-.28751553.16037753-.54506871.58790983-.70400047.40142488-.1488616 1.07786076.00117106 1.20581167.27856864.04319814.09369738.08927466.21199471.13900415.35457792l.03930997.11680217c.05539717.16759437.13470873.41493582.13860471.42816881.02724222.08344874.0471839.13860719.06943813.18441246.00217869.06301886.00217869.06301886.35429398.23177937.41699479-.29154152.41699479-.29154152.38019201-.37525838.00571063-.08773482.00758408-.17356287.00965287-.37317647.00242546-.23402898.00423842-.33154773.00994479-.45966208.01316411-.29554918.0437926-.51142116.09291227-.63864415.09160418-.23801371.25279279-.40993649.4432431-.46667832.24458613-.07380253.51465245-.09215236.73323569-.04710649zm1.21356228 4.27672201c-.20710459.00095412-.37422255.16961903-.37326843.37672361l.016 3.473c.00095412.20710459.16961903.37422251.37672361.37326841.20710459-.0009541.37422255-.16961901.37326843-.37672359l-.016-3.473c-.00095412-.20710459-.16961903-.37422255-.37672361-.37326843zm2.03332759.00229602c-.2071068 0-.375.16789322-.375.375v3.459c0 .20710678.1678932.375.375.375s.375-.16789322.375-.375v-3.459c0-.20710678-.1678932-.375-.375-.375zm-4.01399856.02930704c-.20710289.00126946-.37396385.17018863-.3726944.37729152l.021 3.426c.00126946.20710289.17018863.37396384.37729152.37269444.20710289-.0012695.37396385-.17018867.3726944-.37729156l-.021-3.426c-.00126946-.20710289-.17018863-.37396385-.37729152-.3726944z"
59
+ },
60
+ text: {
61
+ viewBox: "0 0 32 32",
62
+ translate: [13, 8],
63
+ // From mac-cursors/textcursor.svg
64
+ hotspot: [16, 16],
65
+ // Center of I-beam (vertically centered)
66
+ main: "m6.12306605-.48331676c.43304536-.02942018.89723494-.01586641 1.23506765.01110645l.09836607 2.00031187c-.52088553-.02633116-.86402421-.03615261-1.16297111-.01823278-.57216322.1246759-.83397559.26379885-1.13476879.47262866-.20678677.14251521-.54543639.60542479-.68837291.9244994v4.53970853h.998v1.984h-.998v3.57686113c.14285978.3186299.48159131.7805976.69278827.9256073.28177652.1964385.52739561.3374074.74486623.4121252.92617851.1117241.86141186.0439655 1.38886347.0608526l.24148845 1.9771822c-.63869922.0316331-1.03914186.0381475-1.41606129.0122618-.31198863-.0214264-.57343006-.0643378-.77405544-.129216-.41684626-.1296585-.85258908-.3604995-1.32295099-.6884424-.16852556-.1156905-.3571101-.2906327-.54285865-.4981462-.17040902.2017941-.33955796.3725205-.48392771.4855461-.40405946.3138676-.86631905.544191-1.35971316.6990619-.21164232.068207-.47249574.1108318-.78353769.1322303-.43450358.0298922-.90002831.0163041-1.23810501-.010835l-.09691742-2.0002571c.51770616.0263348.86168069.0362399 1.16109487.0181487.6186734-.1394818.87678125-.2519735 1.08726671-.4154673.19712987-.1543365.58456002-.6802379.70170954-.9838289l.01232275-3.57368433h-1.00027293v-1.984h1.002v-4.53315423c-.13203427-.30699537-.51655024-.83390163-.71128328-.98567507-.2013222-.15578504-.43877755-.27368925-.70166256-.36109174-.92774648-.11104657-.86334532-.04378063-1.3908609-.06035307l-.24301648-1.97729129c.64057546-.03160079 1.04058994-.03810767 1.41699023-.01249118.31067274.02114331.57118123.06339129.7795926.13006754.50016024.15848101.96025701.38783055 1.36565801.70154178.14340254.11176212.31252725.28238091.4832615.48453047.18451625-.20650555.37147758-.38041205.53791304-.49511426.47467546-.32956039.90822271-.55967002 1.31895768-.68980909.21133301-.06776711.4720386-.11004715.78312925-.13118199z",
67
+ highlight: ""
68
+ }
69
+ };
70
+ var SHADOW_OFFSET = 1.33;
71
+ var PRESS_OFFSET = 0.59;
72
+ var cursorCache = /* @__PURE__ */ new Map();
73
+ function generateCursorSVG(type, shadowColor, pressed = false) {
74
+ const cursor = CURSOR_PATHS[type];
75
+ const { main, highlight, translate } = cursor;
76
+ const [tx, ty] = translate;
77
+ const scale = CURSOR_SCALES[type];
78
+ if (type === "text") {
79
+ const textShadowOffset = 1.4;
80
+ const textPressOffset = 0.57;
81
+ const scaleX = 0.6;
82
+ const finalScaleX = scale * scaleX;
83
+ const finalScaleY = scale;
84
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
85
+ <g transform="translate(${tx} ${ty}) scale(${finalScaleX}, ${finalScaleY})">
86
+ <path d="${main}" fill="${shadowColor}" fill-rule="evenodd" transform="translate(${textShadowOffset}, ${textShadowOffset})"/>
87
+ <path d="${main}" fill="#000" fill-rule="evenodd"${pressed ? ` transform="translate(${textPressOffset}, ${textPressOffset})"` : ""}/>
88
+ </g>
89
+ </svg>`;
90
+ }
91
+ if (type === "pointer") {
92
+ const bodyTransform2 = pressed ? ` transform="translate(${PRESS_OFFSET}, ${PRESS_OFFSET})"` : "";
93
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
94
+ <g transform="translate(${tx} ${ty}) scale(${scale})">
95
+ <path d="${main}" fill="${shadowColor}" transform="translate(${SHADOW_OFFSET}, ${SHADOW_OFFSET})"/>
96
+ <path d="${main}" fill="#000"${bodyTransform2}/>
97
+ <path d="${highlight}" fill="#fff"${bodyTransform2}/>
98
+ </g>
99
+ </svg>`;
100
+ }
101
+ if (type === "grab") {
102
+ const fingerLines = cursor.fingerLines || [];
103
+ const fingerLinePaths = fingerLines.map(
104
+ (d) => `<path d="${d}" stroke="#000" stroke-linecap="round" stroke-width=".75"/>`
105
+ ).join("");
106
+ const fingerLineShadows = fingerLines.map(
107
+ (d) => `<path d="${d}" stroke="${shadowColor}" stroke-linecap="round" stroke-width=".75"/>`
108
+ ).join("");
109
+ const bodyGroupOpen = pressed ? `<g transform="translate(${PRESS_OFFSET}, ${PRESS_OFFSET})">` : "<g>";
110
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
111
+ <g transform="translate(${tx} ${ty}) scale(${scale})">
112
+ <g transform="translate(${SHADOW_OFFSET}, ${SHADOW_OFFSET})">
113
+ <path d="${main}" fill="${shadowColor}"/>
114
+ ${fingerLineShadows}
115
+ </g>
116
+ ${bodyGroupOpen}
117
+ <path d="${main}" fill="#fff"/>
118
+ <path d="${main}" stroke="#000" stroke-linecap="round" stroke-width=".75" stroke-linejoin="round" fill="none"/>
119
+ ${fingerLinePaths}
120
+ </g>
121
+ </g>
122
+ </svg>`;
123
+ }
124
+ if (type === "grabbing") {
125
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
126
+ <g transform="translate(${tx} ${ty}) scale(${scale})">
127
+ <path d="${main}" fill="${shadowColor}" transform="translate(${SHADOW_OFFSET}, ${SHADOW_OFFSET})"/>
128
+ <path d="${main}" fill="#000" transform="translate(${PRESS_OFFSET}, ${PRESS_OFFSET})"/>
129
+ <path d="${highlight}" fill="#fff" transform="translate(${PRESS_OFFSET}, ${PRESS_OFFSET})"/>
130
+ </g>
131
+ </svg>`;
132
+ }
133
+ const bodyTransform = pressed ? ` transform="translate(${PRESS_OFFSET}, ${PRESS_OFFSET})"` : "";
134
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
135
+ <g transform="translate(${tx} ${ty}) scale(${scale})">
136
+ <path d="${main}" fill="${shadowColor}" transform="translate(${SHADOW_OFFSET}, ${SHADOW_OFFSET})"/>
137
+ <path d="${main}" fill="#fff"${bodyTransform}/>
138
+ <path d="${main}" stroke="#000" stroke-linecap="round" stroke-width=".75" stroke-linejoin="round" fill="none"${bodyTransform}/>
139
+ </g>
140
+ </svg>`;
141
+ }
142
+ function toDataURI(svg) {
143
+ return `data:image/svg+xml,${encodeURIComponent(svg.replace(/\s+/g, " ").trim())}`;
144
+ }
145
+ function generateThemedCursors(shadowColor, pressed = false) {
146
+ const cacheKey = pressed ? `${shadowColor}-pressed` : shadowColor;
147
+ const cached = cursorCache.get(cacheKey);
148
+ if (cached) return cached;
149
+ const types = ["default", "pointer", "grab", "grabbing", "text"];
150
+ const cursors = {};
151
+ for (const type of types) {
152
+ const svg = generateCursorSVG(type, shadowColor, pressed);
153
+ cursors[type] = toDataURI(svg);
154
+ }
155
+ const result = cursors;
156
+ cursorCache.set(cacheKey, result);
157
+ return result;
158
+ }
159
+ function getCursorCSS(dataURI, type, fallback) {
160
+ const hotspot = CURSOR_PATHS[type].hotspot;
161
+ return `url("${dataURI}") ${hotspot[0]} ${hotspot[1]}, ${fallback}`;
162
+ }
163
+ function clearCursorCache() {
164
+ cursorCache.clear();
165
+ }
166
+
167
+ // src/core/apply.ts
168
+ var STYLE_ID = "aura-cursor-styles";
169
+ var CSS_VARS = [
170
+ { prop: "--cursor-default", type: "default", fallback: "auto" },
171
+ { prop: "--cursor-pointer", type: "pointer", fallback: "pointer" },
172
+ { prop: "--cursor-grab", type: "grab", fallback: "grab" },
173
+ { prop: "--cursor-grabbing", type: "grabbing", fallback: "grabbing" },
174
+ { prop: "--cursor-text", type: "text", fallback: "text" }
175
+ ];
176
+ var CSS_VARS_ACTIVE = [
177
+ { prop: "--cursor-default-active", type: "default", fallback: "auto" },
178
+ { prop: "--cursor-pointer-active", type: "pointer", fallback: "pointer" },
179
+ { prop: "--cursor-text-active", type: "text", fallback: "text" }
180
+ ];
181
+ var CURSOR_RULES = `
182
+ @layer cursor-aura {
183
+ html, body { cursor: var(--cursor-default); }
184
+ a, button, [role="button"], input[type="submit"], input[type="button"],
185
+ input[type="reset"], input[type="checkbox"], input[type="radio"],
186
+ select, summary, [onclick], [tabindex]:not([tabindex="-1"]) {
187
+ cursor: var(--cursor-pointer);
188
+ }
189
+ input[type="text"], input[type="email"], input[type="password"],
190
+ input[type="search"], input[type="tel"], input[type="url"],
191
+ input[type="number"], textarea, [contenteditable="true"], [data-cursor="text"] {
192
+ cursor: var(--cursor-text);
193
+ }
194
+ html:active, body:active { cursor: var(--cursor-default-active); }
195
+ a:active, button:active, [role="button"]:active, input[type="submit"]:active,
196
+ input[type="button"]:active, input[type="reset"]:active,
197
+ input[type="checkbox"]:active, input[type="radio"]:active,
198
+ select:active, summary:active, [onclick]:active,
199
+ [tabindex]:not([tabindex="-1"]):active {
200
+ cursor: var(--cursor-pointer-active);
201
+ }
202
+ input[type="text"]:active, input[type="email"]:active, input[type="password"]:active,
203
+ input[type="search"]:active, input[type="tel"]:active, input[type="url"]:active,
204
+ input[type="number"]:active, textarea:active, [contenteditable="true"]:active,
205
+ [data-cursor="text"]:active {
206
+ cursor: var(--cursor-text-active);
207
+ }
208
+ [draggable="true"], .draggable { cursor: var(--cursor-grab); }
209
+ [draggable="true"]:active, .draggable:active, body.dragging {
210
+ cursor: var(--cursor-grabbing);
211
+ }
212
+ }
213
+ `;
214
+ function injectCursorStyles(doc = document) {
215
+ let el = doc.getElementById(STYLE_ID);
216
+ if (!el) {
217
+ el = doc.createElement("style");
218
+ el.id = STYLE_ID;
219
+ el.textContent = CURSOR_RULES;
220
+ doc.head.prepend(el);
221
+ }
222
+ return el;
223
+ }
224
+ function setCursorVariables(color, doc = document) {
225
+ const cursors = generateThemedCursors(color);
226
+ const pressedCursors = generateThemedCursors(color, true);
227
+ const root = doc.documentElement;
228
+ for (const { prop, type, fallback } of CSS_VARS) {
229
+ root.style.setProperty(prop, getCursorCSS(cursors[type], type, fallback));
230
+ }
231
+ for (const { prop, type, fallback } of CSS_VARS_ACTIVE) {
232
+ root.style.setProperty(prop, getCursorCSS(pressedCursors[type], type, fallback));
233
+ }
234
+ }
235
+ function resolveColor(color, doc = document) {
236
+ if (!color.startsWith("var(")) return color;
237
+ const varName = color.slice(4, -1).trim();
238
+ return getComputedStyle(doc.documentElement).getPropertyValue(varName).trim() || "#000";
239
+ }
240
+ function removeCursorStyles(doc = document) {
241
+ doc.getElementById(STYLE_ID)?.remove();
242
+ const root = doc.documentElement;
243
+ for (const { prop } of CSS_VARS) {
244
+ root.style.removeProperty(prop);
245
+ }
246
+ for (const { prop } of CSS_VARS_ACTIVE) {
247
+ root.style.removeProperty(prop);
248
+ }
249
+ }
250
+ function hasPointerDevice(win = window) {
251
+ return win.matchMedia("(pointer: fine)").matches;
252
+ }
253
+ function Aura({ color = "#000" }) {
254
+ const ref = useRef(null);
255
+ const styleRef = useRef(null);
256
+ useLayoutEffect(() => {
257
+ if (!styleRef.current) return;
258
+ styleRef.current.media = "all";
259
+ return () => {
260
+ if (styleRef.current) styleRef.current.media = "not all";
261
+ };
262
+ });
263
+ useEffect(() => {
264
+ const node = ref.current;
265
+ if (!node) return;
266
+ const doc = node.ownerDocument;
267
+ const win = doc.defaultView || window;
268
+ if (!hasPointerDevice(win)) return;
269
+ styleRef.current = injectCursorStyles(doc);
270
+ const apply = () => {
271
+ setCursorVariables(resolveColor(color, doc), doc);
272
+ };
273
+ apply();
274
+ const observer2 = new MutationObserver(() => {
275
+ if (color.startsWith("var(")) apply();
276
+ });
277
+ observer2.observe(doc.documentElement, {
278
+ attributes: true,
279
+ attributeFilter: ["class", "style", "data-theme"]
280
+ });
281
+ win.addEventListener("themechange", apply);
282
+ return () => {
283
+ observer2.disconnect();
284
+ win.removeEventListener("themechange", apply);
285
+ removeCursorStyles(doc);
286
+ styleRef.current = null;
287
+ };
288
+ }, [color]);
289
+ return /* @__PURE__ */ jsx("span", { ref, style: { display: "none" } });
290
+ }
291
+
292
+ // src/vanilla/index.ts
293
+ var currentColor = null;
294
+ var currentDoc = null;
295
+ var observer = null;
296
+ var themeChangeHandler = null;
297
+ function init(options = {}) {
298
+ if (typeof window === "undefined") return;
299
+ const doc = options.document || document;
300
+ const win = doc.defaultView || window;
301
+ if (!hasPointerDevice(win)) return;
302
+ currentDoc = doc;
303
+ const color = options.color || "#000";
304
+ injectCursorStyles(doc);
305
+ applyColor(color);
306
+ observer = new MutationObserver(() => {
307
+ if (currentColor) applyColor(currentColor);
308
+ });
309
+ observer.observe(doc.documentElement, {
310
+ attributes: true,
311
+ attributeFilter: ["class", "style", "data-theme"]
312
+ });
313
+ themeChangeHandler = () => {
314
+ if (currentColor) applyColor(currentColor);
315
+ };
316
+ win.addEventListener("themechange", themeChangeHandler);
317
+ }
318
+ function setColor(color) {
319
+ applyColor(color);
320
+ }
321
+ function destroy() {
322
+ const doc = currentDoc || document;
323
+ const win = doc.defaultView || window;
324
+ if (observer) {
325
+ observer.disconnect();
326
+ observer = null;
327
+ }
328
+ if (themeChangeHandler) {
329
+ win.removeEventListener("themechange", themeChangeHandler);
330
+ themeChangeHandler = null;
331
+ }
332
+ removeCursorStyles(doc);
333
+ clearCursorCache();
334
+ currentColor = null;
335
+ currentDoc = null;
336
+ }
337
+ function applyColor(color) {
338
+ currentColor = color;
339
+ setCursorVariables(color, currentDoc || document);
340
+ }
341
+ var Aura2 = { init, setColor, destroy };
342
+
343
+ export { Aura, Aura2 as AuraVanilla, clearCursorCache, Aura as default, generateCursorSVG, generateThemedCursors, getCursorCSS, toDataURI };
344
+ //# sourceMappingURL=index.js.map
345
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/cursors.ts","../src/core/apply.ts","../src/react/Aura.tsx","../src/vanilla/index.ts"],"names":["bodyTransform","observer","Aura"],"mappings":"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","file":"index.js","sourcesContent":["// Cursor SVG Templates & Generator\n// Based on macOS cursors from github.com/daviddarnes/mac-cursors\n// Inspired by Marcin Wichary's work (aresluna.org)\n\nexport type CursorType = 'default' | 'pointer' | 'grab' | 'grabbing' | 'text'\n\n// Scale factors per cursor type\n// Default arrow uses 1.7x to match visual weight of other cursors\nconst CURSOR_SCALES: Record<CursorType, number> = {\n default: 1.7,\n pointer: 1.5,\n grab: 1.5,\n grabbing: 1.5,\n text: 1.3,\n}\n\n// SVG path data extracted from mac-cursors repo\n// Each cursor has a main (black) and highlight (white) path\n// Grab cursor is special - uses white fill + black stroke + finger lines\n// Canvas: 48x48 (original paths designed for 32x32)\n// Translates match mac-cursors source SVG values\nconst CURSOR_PATHS: Record<CursorType, { main: string; highlight: string; viewBox: string; hotspot: [number, number]; translate: [number, number]; fingerLines?: string[] }> = {\n default: {\n viewBox: '0 0 32 32',\n translate: [10, 7], // From mac-cursors/default.svg\n hotspot: [10, 7], // Arrow tip at origin, so hotspot = translate\n // From mac-cursors/default.svg - white is background stroke, main is black fill\n main: 'm6.431 17 1.765-.941-2.775-5.202h3.604l-8.025-8.043v11.188l2.53-2.442z',\n highlight: 'm6.148 18.473 1.863-1.003 1.615-.839-2.568-4.816h4.332l-11.379-11.408v16.015l3.316-3.221z',\n },\n pointer: {\n viewBox: '0 0 32 32',\n translate: [9, 8], // From mac-cursors/handpointing.svg\n hotspot: [9, 4], // Fingertip ~4px above translate\n main: 'm3.8852309 13.5522788c.15029277.1354048.25406355.2326609.57471053.5372549.31406586.2983172.46594413.439273.60482646.5572091.05791893.0487853.10729946.1792495.12686364.3731628.01609788.1595565.01049553.3375341-.0090192.5090254-.00674888.0593077-.01325791.1020883-.01698742.1224696-.04186639.2287942.13249226.4401222.36507344.4424801.20929712.0021219.37056581.00472.79741331.0123273.10679864.0019014.10679864.0019014.21395196.0037648 1.16029156.0199598 1.75290683.01448 2.1782236-.039003.45462139-.05716.92282087-.6061887 1.32754658-1.2951218.3429437.6096032.818651 1.2048784 1.2990136 1.282277.1525992.0243739.3372104.0319365.5511764.0270146.1595258-.0036697.328349-.0141847.4987188-.0294071.1284742-.0114791.2308379-.0230173.2919821-.0309462.2259121-.0292954.3737346-.2515956.31337-.4712558-.0130388-.0474468-.0339905-.1345046-.0551176-.2441066-.0244927-.1270617-.0421932-.2511642-.0502379-.3642189-.0051002-.0716765-.0061057-.1365707-.0028638-.1926702.0056365-.097781.007395-.1525378.0101327-.2790463.0010457-.0470941.0010457-.0470941.0024433-.0883088.0052898-.134881.0234093-.2629524.0820463-.5422232.0251901-.1212103.1472903-.3531692.3395862-.6402332.0572734-.0854992.1198813-.1747825.1869659-.2669588.127207-.1747861.2641214-.3514011.4010853-.5204043.0820457-.1012383.1454717-.1769623.1807968-.2180763.2962199-.424403.6120842-1.1191696.7281396-1.5253635.111416-.3904017.2005405-1.10937558.2553074-1.81604479.0300143-.40088807.0411211-.72405394.0411211-1.23097561.0000507-.08891816.0000507-.08891816.0002032-.16234685.0002858-.12025251.0003032-.16573976-.0000887-.22195195-.0010706-.15358041-.0055478-.30580145-.0203882-.6940256-.0319191-.81365149-.4778003-1.3396911-1.1348711-1.44115781-.5589865-.08632026-1.2393839.37795756-1.2393839.37795756s-.1514404-.5228127-.2537197-.6842075c-.1661957-.25934741-.5941748-.58982828-.9213451-.65421118-.3365014-.0653413-.7354024-.05811592-1.1017193.00667481-.3207944.05740454-.64034865.34382687-.82518751.65277182-.13223727.22039488-.00786932-.01169164-.14013104-.2396787-.1830552-.31402315-.60932935-.59522407-1.01524567-.67822294-.34396352-.07112559-.73801897-.04403625-1.09795562.06293793-.46304125.13836397-.53675291.49073282-.55516748.38984626-.06158674-.3382385-.06727482-.3160095-.105656-.55729603-.14258072-.89527436-.30213161-1.51473549-.54406219-2.05528331.01391678.0310773-.08860981-.20214701-.12592279-.28256779-.06461002-.13925416-.12910532-.2652956-.19999629-.38652204-.21850342-.37364978-.46891278-.65340904-.7830908-.81233894-.54561037-.27629378-1.3634177-.14183064-1.75105565.31064856-.38495968.44966797-.4491432 1.20149287-.3521966 2.13184003.03702376.36121263.16678627 1.02066144.28444961 1.50812387.04160602.1691894.07805979.32348903.14491578.60851331.01149723.04848415.01149723.04848415.02309483.09698036.05172236.21571896.09707607.39320067.15122332.5879629-.00568154-.02030261.09701461.344086.11888835.42472961.00727686.02691587.00727686.02691587.01448296.05395339.04082856.15377935.08074083.31959314.14309954.5963099.03412572.1521447.06742545.31468601.09999775.48699018.08883553.46993091.089274.37207374.00375852.27186198-.05907319-.06922522-.11463055-.13209255-.16830659-.19003644-.09976937-.10770214-.19148509-.19677225-.2785569-.2678141-.6343975-.51905295-1.02312991-.74839425-1.55681885-.79878106-.87541567-.08410158-1.70619803.53426712-1.83111632 1.36882761-.07682697.51169638-.05207639.74723271.18463583 1.19942735.13026223.24432805.35060714.53942202.76172732 1.04735429.02515953.031068.02515953.031068.05030428.06206416.50464537.62186746.55962098.69095396.67961467.86473786.32435479.4706845 1.1139501 1.8221455 1.25748612 2.0035872z',\n highlight: 'm1.68266944 9.2716401c-.02488625-.03067752-.02488625-.03067752-.04970567-.06132555-.37729166-.46613768-.58418002-.74321015-.68156241-.9258495-.15281729-.29195235-.1611316-.37107459-.10605794-.73788601.06473349-.43247455.53181583-.78013371 1.01829549-.73339767.33660502.03178017.63068475.20527903 1.15339692.63295262.0565942.04617564.12482853.1124417.20288232.19670163.04616569.04983637.09513192.10524534.14800114.16720042.0794093.0930562.34702847.42052231.30761424.37286894.05814283.06991619.09971852.12407704.14721655.19045018.0941062.13434104.14705111.20894642.21874992.30454484-.0336171-.04487143.21473082.29843305.26732159.34863333.27859812.26593456.68203289.04195871.65675979-.31244785-.00421914-.05916537-.01812774-.12308431-.04717934-.23466885-.11487425-.81923739-.15505751-1.08218312-.24678252-1.56739907-.03407352-.18024544-.06905328-.35098727-.10521102-.5121905-.06435409-.28557213-.10635725-.46007245-.14994794-.62425526-.00774801-.02907063-.00774801-.02907063-.01552357-.05783095-.02300644-.08481964-.12725123-.45470311-.12030828-.42989063-.05134381-.18468043-.0945453-.35373996-.14431997-.56133562-.01130896-.04728909-.01130896-.04728909-.02259904-.09489949-.06649254-.28350912-.10387999-.44176072-.14606063-.6132721-.10998732-.45567652-.23425389-1.08719519-.2671036-1.40768017-.07546665-.72422018-.02339381-1.33418457.17582284-1.56688778.15554834-.1815673.59641015-.25405339.84271752-.12932486.16107512.0814814.32204278.26131571.47435101.521769.05764302.09857191.11172763.20426801.16708381.32357735.0335256.07225783.13292567.29837003.12172905.27336705.21032209.46992469.354801 1.03086841.48791736 1.86671535.03939531.24766201.08813662.52823537.15063928.87150416.01857903.10178746.01857903.10178746.03722922.20314381.30139226 1.63533599.27933797 1.51139381.28367122 1.64182468.01580667.47578071.71810567.4869267.74900255.01188722.00979855-.15065269.00630989-.2851661-.01107827-.67146517-.00245496-.05465243-.00245496-.05465243-.00481877-.10910149-.01521525-.35590459-.01433687-.56066672.00670546-.67705709.03834708-.21223125.22887-.4499778.40434754-.50241339.24641865-.07323589.51640341-.09179599.73269877-.04707051.20703808.0423346.44864736.20171736.51796318.32062499.08353628.14399789.15516008.36337367.21006107.63530456.04431149.21947986.07480439.45493493.0962536.70624261.00667352.0781897.01103024.13859819.01772256.23854675.00285005.04183594.00285005.04183594.00568968.07635213.00160285.01731471.00160285.01731471.00551199.04467336.00303535.01917374.00303535.01917374.01734216.06773608.00727602.13782339.00727602.13782339.56081544.18893151.16530264-.19982737.16530264-.19982737.16077268-.23486454.02708074-.1183491.04365279-.250265.06727822-.49813693.01508098-.16112409.02268576-.24033521.03157416-.32249887.036794-.34012028.0835164-.55621578.140511-.65120691.0707148-.11819408.3197845-.28280909.4314962-.30279961.2805348-.04961763.5886064-.0551978.8264635-.00901194.1077347.021202.3705429.22413969.4327499.32121002.1277282.20156171.2519621.8513817.3219188 1.49611734-.0110122.04228902-.0110122.04228902.1607163.28760404.5903408-.06730286.5903408-.06730286.5737568-.17389206.0155734-.03799147.0279666-.08191522.0455068-.15013809.0421947-.1597068.0701719-.25243998.1118273-.35635899.0288165-.07188915.0591935-.13335501.0903398-.18227881.120675-.18992919.4330876-.31896311.7070596-.2766556.2942545.0454396.4817569.26665023.4998934.72896761.0145423.38042999.0188438.52667972.0198445.67022961.0003693.0529684.0003531.09548963.0000723.21509672-.0001536.07391241-.0001536.07391241-.000205.16397385 0 .48892448-.010469.79353263-.0389535 1.17400348-.0506294.653266-.1361064 1.34281542-.228649 1.66708482-.094456.330596-.3764591.9508823-.5997469 1.2734975-.0158389.0153017-.0838055.0964468-.1706932.2036597-.1445918.1784155-.2892331.364998-.4248114.5512865-.0725632.099704-.140705.1968792-.2036767.2908847-.2436695.3637558-.4000227.6607868-.4506249.9042828-.0664376.3164194-.0901813.4842425-.0973169.666189-.0017426.0515155-.0017426.0515155-.0028439.1014735-.0025547.1180556-.0040857.165727-.0090621.2520573-.0052398.0906702-.0037444.1871795.0035093.2891187.0103883.145992.0000001.3454812.0000001.3454812s-.1266332-.0118299-.2678551-.0085813c-.1725177.0039685-.3159859-.0019087-.4151297-.0177442-.143046-.0230487-.5293508-.5064503-.7271506-.8830611-.3022704-.5764228-1.03604858-.5484427-1.33684295-.0394061-.27130191.4618137-.65965243.9172085-.77493336.9317029-.37460536.047106-.95471158.0524702-2.07175566.0332544-.10679478-.0018572-.10679478-.0018572-.21348729-.0037567-.42889761-.0076439-.41241496.0647655-.40363307-.0124079.02506967-.2203068.02222332-.1790312.00000011-.3992999-.03726222-.36933-.15125405-.6704984-.38877094-.8705429-.12286946-.1043424-.26983033-.2407345-.56500741-.5211097-.33722428-.3203411-.44283686-.4193233-.57299128-.5337266l-.80130455-.8907189c-.08795856-.1124788-.86002339-1.4339349-1.21248613-1.9454077-.13710846-.19857111-.18839645-.26302343-.71461353-.9114734zm9.50873056.0037599v3.459c0 .5.75.5.75 0v-3.459c0-.5-.75-.5-.75 0zm-2.03159602-.00057241.016 3.47300001c.00230346.4999947.7522955.4965395.74999204-.0034552l-.016-3.47299999c-.00230346-.4999947-.7522955-.49653951-.74999204.00345518zm-1.20911102 3.45357381-.021-3.42599996c-.00306475-.4999906-.75305066-.49539349-.74998592.00459712l.021 3.42600004c.00306475.4999906.75305066.4953935.74998592-.0045972z',\n },\n grab: {\n viewBox: '0 0 32 32',\n translate: [7, 6], // From mac-cursors/handopen.svg\n hotspot: [11, 9], // Center of palm area\n // Hand open cursor uses white fill + black stroke structure\n main: 'm4.5557 8.5742c-.098-.375-.196-.847-.406-1.552-.167-.557-.342-.859-.47-1.233-.155-.455-.303-.721-.496-1.181-.139-.329-.364-1.048-.457-1.44-.119-.509.033-.924.244-1.206.253-.339.962-.49 1.357-.351.371.13.744.512.916.788.288.46.357.632.717 1.542.393.992.564 1.918.611 2.231l.085.452c-.001-.04-.043-1.122-.044-1.162-.035-1.029-.06-1.823-.038-2.939.002-.126.064-.587.084-.715.078-.5.305-.8.673-.979.412-.201.926-.215 1.401-.017.423.173.626.55.687 1.022.014.109.094.987.093 1.107-.013 1.025.006 1.641.015 2.174.004.231.003 1.625.017 1.469.061-.656.094-3.189.344-3.942.144-.433.405-.746.794-.929.431-.203 1.113-.07 1.404.243.285.305.446.692.482 1.153.032.405-.019.897-.02 1.245 0 .867-.021 1.324-.037 2.121-.001.038-.015.298.023.182.094-.28.188-.542.266-.745.049-.125.241-.614.359-.859.114-.234.211-.369.415-.688.2-.313.415-.448.668-.561.54-.235 1.109.112 1.301.591.086.215.009.713-.028 1.105-.061.647-.254 1.306-.352 1.648-.128.447-.274 1.235-.34 1.601-.072.394-.234 1.382-.359 1.82-.086.301-.371.978-.652 1.384 0 0-1.074 1.25-1.192 1.812-.117.563-.078.567-.101.965-.024.399.121.923.121.923s-.802.104-1.234.034c-.391-.062-.875-.841-1-1.078-.172-.328-.539-.265-.682-.023-.225.383-.709 1.07-1.051 1.113-.668.084-2.054.03-3.139.02 0 0 .185-1.011-.227-1.358-.305-.26-.83-.784-1.144-1.06l-.832-.921c-.284-.36-.629-1.093-1.243-1.985-.348-.504-1.027-1.085-1.284-1.579-.223-.425-.331-.954-.19-1.325.225-.594.675-.897 1.362-.832.519.05.848.206 1.238.537.225.19.573.534.75.748.163.195.203.276.377.509.23.307.302.459.214.121',\n highlight: '', // Grab uses stroke-based rendering, not highlight fill\n // Additional finger line paths for grab cursor\n fingerLines: [\n 'm11.566 12.734v-3.459',\n 'm9.551 12.746-.016-3.473',\n 'm7.555 9.305.021 3.426'\n ],\n },\n grabbing: {\n viewBox: '0 0 32 32',\n translate: [8, 9], // From mac-cursors/handgrabbing.svg\n hotspot: [12, 14], // Center of closed palm\n main: 'm3.44281398 1.68449726c-.74326136.27630142-1.05584685.8131257-1.07636853 1.38003696-.01344897.37336893.06665513.72649286.23114214 1.18694303-.02596219-.07267623.09676488.29282004.12116236.37362273.05052942.16918921-.4865367-.05865774-.81377307.00741883-.36363321.07113868-.84783757.38332307-1.10006887.79754775-.29643467.48542737-.3109609 1.04368567-.08235979 2.04824266.12491868.54736183.36572145 1.00836814.71076689 1.44594879.15329951.1944118.5713628.64726015.60307236.6875974l.84854343.94062339c.15080214.1358526.25794954.2361946.57590427.5380259.3147558.2987762.4647038.4380078.60308951.555976.05846214.0492474.10784267.1797116.12740685.3736249.01609788.1595565.01049553.3375341-.0090192.5090254-.00674888.0593077-.01325791.1020883-.01698742.1224696-.04189161.228932.13269563.4403386.36541902.4424835.21585671.0019894.38528595.0046546.82216479.0123538.09483476.0016698.09483476.0016698.18993053.0033129 1.16876447.0200186 1.75308289.0147904 2.17807912-.0385723.45429894-.0572869.92650915-.6110188 1.32698393-1.2957591.34289141.6108338.81859723 1.2057867 1.2995685 1.2820532.1510118.0244148.3353555.0322555.548787.0275887.1606725-.0035131.3307029-.0140241.5021961-.0293376.1276907-.0114022.2293359-.0228648.29003-.0307451.2258836-.0293282.373669-.251611.3133108-.4712481-.0130351-.0474332-.0339838-.1345011-.0551094-.2441635-.0245945-.1276687-.0423383-.2523857-.0503381-.365988-.0050217-.0713101-.0059948-.1359317-.0027687-.1918983.0059157-.0980798.0077938-.1530073.0108033-.281125.0010795-.0448938.0010795-.0448938.0024606-.0845172.0054208-.1364475.0233824-.2649146.0815132-.544638.0250088-.1201275.1473169-.352189.3398902-.639435.0571394-.0852302.1195783-.1742239.1864664-.26609712.1272143-.17473362.2641361-.35131772.4011075-.52030772.082051-.10123129.145482-.17695689.1808122-.21807676.2967593-.42378347.612817-1.11823437.7291396-1.52536348.1117407-.39153936.202351-1.12501196.254373-1.81690429.029923-.39968605.0410555-.72381216.0410555-1.23011613.0000742-.09758414.0000742-.09758414.0002975-.17670236.0003569-.11115478.0003569-.11115478.000115-.20711835-.0008934-.15683883-.0055282-.31323355-.0207085-.69507578-.0313109-.81293139-.4771727-1.33911388-1.1344906-1.44058831-.559108-.08631314-1.0586051.08188477-1.2779293.31625977-.0755526.08073733.0036753-.2781823-.2159489-.62316278-.1644465-.25841586-.593184-.58905957-.9209287-.65355552-.335487-.06535532-.73539548-.05811715-1.1017193.00667481-.32093157.05742909-.68608434.33741751-.87176225.64688068-.12411885.20686477.03884667-.00592296-.09368743-.23401341-.18231052-.31422641-.60754287-.59486422-1.01411454-.67799709-.34643562-.07139428-.74182572-.04452925-1.09945614.0633873-.43336319.1291117-1.01795827.61460976-.94899189 1.15552627-.34375-.54091651-1.25026717-.691379-1.97906097-.42111797z',\n highlight: 'm7.31951013 1.62138197c.20710357.04234751.44724204.20083012.51632974.31990811.08404358.1446387.15562749.36413806.21048667.6366124.02933373.14569467.12179446 1.2125285.29383112 1.32370243.41279229.04533731.41279229.04533731.52658055-.12364345.03545705-.07383858.03545705-.07383858.04226523-.1029106.01416796-.06009544.02463332-.12677987.0351322-.21754028l.00854738-.07915386.00047673-.00942804.00327525-.03167185c.01085148-.11424313.04184125-.4312127.05388392-.53034902.03788792-.31189663.08766449-.52757784.13944093-.6138719.0713024-.11883734.31942298-.28274442.43149612-.30279961.2804398-.04960082.58940103-.05519288.82623993-.00905543.1084394.02134018.3709471.22378689.432331.32024744.1291079.20279957.2524316.84889766.3225486 1.4970065-.0102194.04624251-.0102194.04624251.1640069.28984194.5843296-.06677889.5843296-.06677889.5703629-.17490247.0159511-.03856429.0284824-.08294031.045969-.15118961.0423876-.16089067.0697594-.25204451.111066-.35549917.0288558-.07227096.0592914-.13391873.0904889-.18278042.1209187-.19031132.4335712-.319392.7077174-.27707028.2943447.04543991.4816904.26653537.4994912.72869815.0148821.37434892.0193146.5239164.0201469.6700184l-.0004247.37954865c0 .48831141-.0104951.79388164-.0389535 1.17400348-.0480918.63962116-.1348512 1.34192123-.227649 1.66708484-.0946325.33121345-.3766371.95084197-.6003915 1.27298482-.0161892.01580846-.0841508.09694273-.1710333.20413492-.1445842.17838247-.2892181.36491271-.4247891.5511244-.0723398.09936149-.1402862.19620479-.2030964.2898938-.2440054.36396314-.400553.66098894-.4512157.90434304-.0659304.3172546-.0893838.4850003-.0966379.6675968-.0017072.0490782-.0017072.0490782-.002845.096677-.0028064.119476-.004437.1671639-.0097087.2545848-.0052654.091322-.0038193.187354.00332.2887353.0103318.1467182.1058713.3478531.1058713.3478531s-.2321503-.0119819-.3742084-.0088758c-.1718098.0037567-.3147843-.0023244-.4138162-.0183342-.1440353-.0228411-.53014068-.5057331-.7278511-.8821737-.30227042-.5764228-1.03604858-.5484427-1.33684295-.0394061-.26854779.4591613-.65918083.9172326-.7740684.9317199-.37404082.0469647-.94643778.0520862-2.07160079.0328144-.09480875-.0016381-.46003446-.0128683-.64600494-.0157445-.18597048-.0028763.05008807-.1790283.02786486-.399297-.03726222-.36933-.15125405-.6704984-.38877094-.8705429-.12241569-.1043631-.26774964-.2393104-.56509654-.5215613-.33323493-.3163366-.44236499-.4185353-.57290215-.533275l-.80130455-.89071892c-.03955779-.05174211-.45812831-.5051399-.5872217-.6688539-.28069963-.35597842-.47062947-.71959073-.56844755-1.14820437-.18921973-.83150113-.1793328-1.21146622-.00855589-1.49112273.13743587-.2257023.43815377-.4195862.60596039-.45241793.17165981-.03465512.55153059-.01648617.62179422.02229321.09902279.05401056.13357243.07300285.16379074.09097645.03572494.02124891.05965747.03799198.08182912.05708809.03426437.02951139.07235014.07170412.12420211.14044502.03611591.04821025.07806642.1053997.1423779.19304882.06054643.0816627.09183576.12069421.13369221.1590035.28038907.25662728.68391532.03238058.65052057-.32606956-.00567036-.06086415-.02203766-.12694598-.05458621-.23708502-.04356824-.15021272.00433013-.05284275-.26002629-.56642281-.08720664-.16942124-.13955864-.28835362-.17428227-.4046158l-.03412852-.10219113c-.03838756-.11059767-.09558223-.26854489-.12612861-.35199347l-.02009957-.05467087.002.008-.05974804-.17751191c-.09232236-.28807194-.13413567-.51358087-.12645475-.72681781.01040781-.28751553.16037753-.54506871.58790983-.70400047.40142488-.1488616 1.07786076.00117106 1.20581167.27856864.04319814.09369738.08927466.21199471.13900415.35457792l.03930997.11680217c.05539717.16759437.13470873.41493582.13860471.42816881.02724222.08344874.0471839.13860719.06943813.18441246.00217869.06301886.00217869.06301886.35429398.23177937.41699479-.29154152.41699479-.29154152.38019201-.37525838.00571063-.08773482.00758408-.17356287.00965287-.37317647.00242546-.23402898.00423842-.33154773.00994479-.45966208.01316411-.29554918.0437926-.51142116.09291227-.63864415.09160418-.23801371.25279279-.40993649.4432431-.46667832.24458613-.07380253.51465245-.09215236.73323569-.04710649zm1.21356228 4.27672201c-.20710459.00095412-.37422255.16961903-.37326843.37672361l.016 3.473c.00095412.20710459.16961903.37422251.37672361.37326841.20710459-.0009541.37422255-.16961901.37326843-.37672359l-.016-3.473c-.00095412-.20710459-.16961903-.37422255-.37672361-.37326843zm2.03332759.00229602c-.2071068 0-.375.16789322-.375.375v3.459c0 .20710678.1678932.375.375.375s.375-.16789322.375-.375v-3.459c0-.20710678-.1678932-.375-.375-.375zm-4.01399856.02930704c-.20710289.00126946-.37396385.17018863-.3726944.37729152l.021 3.426c.00126946.20710289.17018863.37396384.37729152.37269444.20710289-.0012695.37396385-.17018867.3726944-.37729156l-.021-3.426c-.00126946-.20710289-.17018863-.37396385-.37729152-.3726944z',\n },\n text: {\n viewBox: '0 0 32 32',\n translate: [13, 8], // From mac-cursors/textcursor.svg\n hotspot: [16, 16], // Center of I-beam (vertically centered)\n main: 'm6.12306605-.48331676c.43304536-.02942018.89723494-.01586641 1.23506765.01110645l.09836607 2.00031187c-.52088553-.02633116-.86402421-.03615261-1.16297111-.01823278-.57216322.1246759-.83397559.26379885-1.13476879.47262866-.20678677.14251521-.54543639.60542479-.68837291.9244994v4.53970853h.998v1.984h-.998v3.57686113c.14285978.3186299.48159131.7805976.69278827.9256073.28177652.1964385.52739561.3374074.74486623.4121252.92617851.1117241.86141186.0439655 1.38886347.0608526l.24148845 1.9771822c-.63869922.0316331-1.03914186.0381475-1.41606129.0122618-.31198863-.0214264-.57343006-.0643378-.77405544-.129216-.41684626-.1296585-.85258908-.3604995-1.32295099-.6884424-.16852556-.1156905-.3571101-.2906327-.54285865-.4981462-.17040902.2017941-.33955796.3725205-.48392771.4855461-.40405946.3138676-.86631905.544191-1.35971316.6990619-.21164232.068207-.47249574.1108318-.78353769.1322303-.43450358.0298922-.90002831.0163041-1.23810501-.010835l-.09691742-2.0002571c.51770616.0263348.86168069.0362399 1.16109487.0181487.6186734-.1394818.87678125-.2519735 1.08726671-.4154673.19712987-.1543365.58456002-.6802379.70170954-.9838289l.01232275-3.57368433h-1.00027293v-1.984h1.002v-4.53315423c-.13203427-.30699537-.51655024-.83390163-.71128328-.98567507-.2013222-.15578504-.43877755-.27368925-.70166256-.36109174-.92774648-.11104657-.86334532-.04378063-1.3908609-.06035307l-.24301648-1.97729129c.64057546-.03160079 1.04058994-.03810767 1.41699023-.01249118.31067274.02114331.57118123.06339129.7795926.13006754.50016024.15848101.96025701.38783055 1.36565801.70154178.14340254.11176212.31252725.28238091.4832615.48453047.18451625-.20650555.37147758-.38041205.53791304-.49511426.47467546-.32956039.90822271-.55967002 1.31895768-.68980909.21133301-.06776711.4720386-.11004715.78312925-.13118199z',\n highlight: '',\n },\n}\n\n// Shadow offset in path coordinates (before scaling)\n// Effective pixel offset = SHADOW_OFFSET * scale\nconst SHADOW_OFFSET = 1.33\n\n// Body displacement when pressed — cursor slides toward shadow\n// Shadow stays at full SHADOW_OFFSET; body moves by PRESS_OFFSET\nconst PRESS_OFFSET = 0.59\n\n// Cache for generated cursors\nconst cursorCache = new Map<string, Record<CursorType, string>>()\n\n/**\n * Generates an SVG cursor with a colored shadow baked in\n * Uses variable scale per cursor type (default: 1.7x, others: 1.5x)\n * @param type - The cursor type\n * @param shadowColor - The shadow color\n * @param pressed - When true, uses smaller shadow offset for \"pressed\" feel\n */\nexport function generateCursorSVG(type: CursorType, shadowColor: string, pressed = false): string {\n const cursor = CURSOR_PATHS[type]\n const { main, highlight, translate } = cursor\n const [tx, ty] = translate\n const scale = CURSOR_SCALES[type]\n // For text cursor - black fill only + matching shadow (no white border)\n if (type === 'text') {\n const textShadowOffset = 1.4\n const textPressOffset = 0.57\n const scaleX = 0.6 // Squish horizontally for thinner appearance\n // SVG uses scale(x, y) not scaleX() - combine scale and scaleX\n const finalScaleX = scale * scaleX\n const finalScaleY = scale\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\">\n <g transform=\"translate(${tx} ${ty}) scale(${finalScaleX}, ${finalScaleY})\">\n <path d=\"${main}\" fill=\"${shadowColor}\" fill-rule=\"evenodd\" transform=\"translate(${textShadowOffset}, ${textShadowOffset})\"/>\n <path d=\"${main}\" fill=\"#000\" fill-rule=\"evenodd\"${pressed ? ` transform=\"translate(${textPressOffset}, ${textPressOffset})\"` : ''}/>\n </g>\n </svg>`\n }\n\n // For pointer cursor - same structure as original: black base + white highlight overlay\n // The white highlight sits on top of black main, creating white hand with black edges\n if (type === 'pointer') {\n const bodyTransform = pressed ? ` transform=\"translate(${PRESS_OFFSET}, ${PRESS_OFFSET})\"` : ''\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\">\n <g transform=\"translate(${tx} ${ty}) scale(${scale})\">\n <path d=\"${main}\" fill=\"${shadowColor}\" transform=\"translate(${SHADOW_OFFSET}, ${SHADOW_OFFSET})\"/>\n <path d=\"${main}\" fill=\"#000\"${bodyTransform}/>\n <path d=\"${highlight}\" fill=\"#fff\"${bodyTransform}/>\n </g>\n </svg>`\n }\n\n // For grab cursor - white fill + black stroke\n if (type === 'grab') {\n const fingerLines = cursor.fingerLines || []\n const fingerLinePaths = fingerLines.map(d =>\n `<path d=\"${d}\" stroke=\"#000\" stroke-linecap=\"round\" stroke-width=\".75\"/>`\n ).join('')\n const fingerLineShadows = fingerLines.map(d =>\n `<path d=\"${d}\" stroke=\"${shadowColor}\" stroke-linecap=\"round\" stroke-width=\".75\"/>`\n ).join('')\n\n const bodyGroupOpen = pressed\n ? `<g transform=\"translate(${PRESS_OFFSET}, ${PRESS_OFFSET})\">`\n : '<g>'\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\">\n <g transform=\"translate(${tx} ${ty}) scale(${scale})\">\n <g transform=\"translate(${SHADOW_OFFSET}, ${SHADOW_OFFSET})\">\n <path d=\"${main}\" fill=\"${shadowColor}\"/>\n ${fingerLineShadows}\n </g>\n ${bodyGroupOpen}\n <path d=\"${main}\" fill=\"#fff\"/>\n <path d=\"${main}\" stroke=\"#000\" stroke-linecap=\"round\" stroke-width=\".75\" stroke-linejoin=\"round\" fill=\"none\"/>\n ${fingerLinePaths}\n </g>\n </g>\n </svg>`\n }\n\n // For grabbing cursor — shadow at full offset, body always shifted (grabbing IS the pressed state)\n if (type === 'grabbing') {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\">\n <g transform=\"translate(${tx} ${ty}) scale(${scale})\">\n <path d=\"${main}\" fill=\"${shadowColor}\" transform=\"translate(${SHADOW_OFFSET}, ${SHADOW_OFFSET})\"/>\n <path d=\"${main}\" fill=\"#000\" transform=\"translate(${PRESS_OFFSET}, ${PRESS_OFFSET})\"/>\n <path d=\"${highlight}\" fill=\"#fff\" transform=\"translate(${PRESS_OFFSET}, ${PRESS_OFFSET})\"/>\n </g>\n </svg>`\n }\n\n // Default arrow cursor - white fill + black stroke\n const bodyTransform = pressed ? ` transform=\"translate(${PRESS_OFFSET}, ${PRESS_OFFSET})\"` : ''\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\">\n <g transform=\"translate(${tx} ${ty}) scale(${scale})\">\n <path d=\"${main}\" fill=\"${shadowColor}\" transform=\"translate(${SHADOW_OFFSET}, ${SHADOW_OFFSET})\"/>\n <path d=\"${main}\" fill=\"#fff\"${bodyTransform}/>\n <path d=\"${main}\" stroke=\"#000\" stroke-linecap=\"round\" stroke-width=\".75\" stroke-linejoin=\"round\" fill=\"none\"${bodyTransform}/>\n </g>\n </svg>`\n}\n\n/**\n * Converts SVG string to a data URI for use in CSS cursor property\n */\nexport function toDataURI(svg: string): string {\n return `data:image/svg+xml,${encodeURIComponent(svg.replace(/\\s+/g, ' ').trim())}`\n}\n\n/**\n * Generates all cursor data URIs using the provided shadow color\n * Results are cached for performance\n * @param pressed - When true, generates cursors with smaller shadow offset\n */\nexport function generateThemedCursors(shadowColor: string, pressed = false): Record<CursorType, string> {\n // Check cache first\n const cacheKey = pressed ? `${shadowColor}-pressed` : shadowColor\n const cached = cursorCache.get(cacheKey)\n if (cached) return cached\n\n const types: CursorType[] = ['default', 'pointer', 'grab', 'grabbing', 'text']\n const cursors: Partial<Record<CursorType, string>> = {}\n\n for (const type of types) {\n const svg = generateCursorSVG(type, shadowColor, pressed)\n cursors[type] = toDataURI(svg)\n }\n\n const result = cursors as Record<CursorType, string>\n cursorCache.set(cacheKey, result)\n return result\n}\n\n/**\n * Returns the CSS cursor value with hotspot coordinates\n */\nexport function getCursorCSS(dataURI: string, type: CursorType, fallback: string): string {\n const hotspot = CURSOR_PATHS[type].hotspot\n return `url(\"${dataURI}\") ${hotspot[0]} ${hotspot[1]}, ${fallback}`\n}\n\n/**\n * Clears the cursor cache\n */\nexport function clearCursorCache(): void {\n cursorCache.clear()\n}\n","import { generateThemedCursors, getCursorCSS, type CursorType } from './cursors'\n\nconst STYLE_ID = 'aura-cursor-styles'\n\nconst CSS_VARS: ReadonlyArray<{\n prop: string\n type: CursorType\n fallback: string\n}> = [\n { prop: '--cursor-default', type: 'default', fallback: 'auto' },\n { prop: '--cursor-pointer', type: 'pointer', fallback: 'pointer' },\n { prop: '--cursor-grab', type: 'grab', fallback: 'grab' },\n { prop: '--cursor-grabbing', type: 'grabbing', fallback: 'grabbing' },\n { prop: '--cursor-text', type: 'text', fallback: 'text' },\n]\n\n// Active/pressed variants — smaller shadow for \"pressed closer to surface\" feel\nconst CSS_VARS_ACTIVE: ReadonlyArray<{\n prop: string\n type: CursorType\n fallback: string\n}> = [\n { prop: '--cursor-default-active', type: 'default', fallback: 'auto' },\n { prop: '--cursor-pointer-active', type: 'pointer', fallback: 'pointer' },\n { prop: '--cursor-text-active', type: 'text', fallback: 'text' },\n]\n\n// Static CSS rules referencing custom properties. No !important.\n// Wrapped in @layer so consumer styles (layered or unlayered) can override.\nconst CURSOR_RULES = `\n@layer cursor-aura {\n html, body { cursor: var(--cursor-default); }\n a, button, [role=\"button\"], input[type=\"submit\"], input[type=\"button\"],\n input[type=\"reset\"], input[type=\"checkbox\"], input[type=\"radio\"],\n select, summary, [onclick], [tabindex]:not([tabindex=\"-1\"]) {\n cursor: var(--cursor-pointer);\n }\n input[type=\"text\"], input[type=\"email\"], input[type=\"password\"],\n input[type=\"search\"], input[type=\"tel\"], input[type=\"url\"],\n input[type=\"number\"], textarea, [contenteditable=\"true\"], [data-cursor=\"text\"] {\n cursor: var(--cursor-text);\n }\n html:active, body:active { cursor: var(--cursor-default-active); }\n a:active, button:active, [role=\"button\"]:active, input[type=\"submit\"]:active,\n input[type=\"button\"]:active, input[type=\"reset\"]:active,\n input[type=\"checkbox\"]:active, input[type=\"radio\"]:active,\n select:active, summary:active, [onclick]:active,\n [tabindex]:not([tabindex=\"-1\"]):active {\n cursor: var(--cursor-pointer-active);\n }\n input[type=\"text\"]:active, input[type=\"email\"]:active, input[type=\"password\"]:active,\n input[type=\"search\"]:active, input[type=\"tel\"]:active, input[type=\"url\"]:active,\n input[type=\"number\"]:active, textarea:active, [contenteditable=\"true\"]:active,\n [data-cursor=\"text\"]:active {\n cursor: var(--cursor-text-active);\n }\n [draggable=\"true\"], .draggable { cursor: var(--cursor-grab); }\n [draggable=\"true\"]:active, .draggable:active, body.dragging {\n cursor: var(--cursor-grabbing);\n }\n}\n`\n\n/**\n * Injects the static cursor CSS rules into <head>.\n * Idempotent: reuses existing element if present.\n * Rules are wrapped in @layer cursor-aura so consumer styles can override.\n * Portal-proof: accepts an optional document for correct context in\n * iframes, portals, or pop-out windows.\n */\nexport function injectCursorStyles(doc: Document = document): HTMLStyleElement {\n let el = doc.getElementById(STYLE_ID) as HTMLStyleElement | null\n if (!el) {\n el = doc.createElement('style')\n el.id = STYLE_ID\n el.textContent = CURSOR_RULES\n doc.head.prepend(el)\n }\n return el\n}\n\n/**\n * Sets the 8 --cursor-* CSS custom properties on :root.\n * 5 normal + 3 active/pressed variants with smaller shadow offset.\n * `color` must be a resolved value (not a var() reference).\n */\nexport function setCursorVariables(color: string, doc: Document = document): void {\n const cursors = generateThemedCursors(color)\n const pressedCursors = generateThemedCursors(color, true)\n const root = doc.documentElement\n for (const { prop, type, fallback } of CSS_VARS) {\n root.style.setProperty(prop, getCursorCSS(cursors[type], type, fallback))\n }\n for (const { prop, type, fallback } of CSS_VARS_ACTIVE) {\n root.style.setProperty(prop, getCursorCSS(pressedCursors[type], type, fallback))\n }\n}\n\n/**\n * If `color` starts with \"var(\", reads the computed value from\n * document.documentElement. Otherwise returns `color` unchanged.\n */\nexport function resolveColor(color: string, doc: Document = document): string {\n if (!color.startsWith('var(')) return color\n const varName = color.slice(4, -1).trim()\n return getComputedStyle(doc.documentElement).getPropertyValue(varName).trim() || '#000'\n}\n\n/**\n * Removes the <style> element and all 8 CSS custom properties from :root.\n */\nexport function removeCursorStyles(doc: Document = document): void {\n doc.getElementById(STYLE_ID)?.remove()\n const root = doc.documentElement\n for (const { prop } of CSS_VARS) {\n root.style.removeProperty(prop)\n }\n for (const { prop } of CSS_VARS_ACTIVE) {\n root.style.removeProperty(prop)\n }\n}\n\n/**\n * Removes the 8 CSS custom properties from :root without removing the\n * <style> element. Used for Activity-proof cleanup where the style tag\n * is disabled via media attribute rather than removed.\n */\nexport function removeCursorVariables(doc: Document = document): void {\n const root = doc.documentElement\n for (const { prop } of CSS_VARS) {\n root.style.removeProperty(prop)\n }\n for (const { prop } of CSS_VARS_ACTIVE) {\n root.style.removeProperty(prop)\n }\n}\n\n/**\n * Returns true when the primary pointing device is a mouse or trackpad.\n * Hybrid devices (laptop + touchscreen) return true.\n * Touch-only devices return false.\n * Portal-proof: accepts an optional window for correct context.\n */\nexport function hasPointerDevice(win: Window = window): boolean {\n return win.matchMedia('(pointer: fine)').matches\n}\n","'use client'\n\nimport { useEffect, useLayoutEffect, useRef } from 'react'\nimport {\n injectCursorStyles,\n setCursorVariables,\n resolveColor,\n removeCursorStyles,\n removeCursorVariables,\n hasPointerDevice,\n} from '../core/apply'\n\nexport interface AuraProps {\n /**\n * The shadow color for the cursor.\n * Accepts any valid CSS color: hex, rgb, hsl, or CSS variable.\n * @default '#000'\n */\n color?: string\n}\n\n/**\n * Aura - Themed cursor shadows for the web\n *\n * Renders a hidden marker element to detect the correct document context\n * (portal-proof). Applies custom cursors via CSS custom properties on the\n * document root. The shadow color updates automatically when the\n * color prop changes.\n *\n * @example\n * ```tsx\n * <Aura color=\"#0C3EFF\" />\n * <Aura color=\"var(--theme-color)\" />\n * ```\n */\nexport function Aura({ color = '#000' }: AuraProps) {\n const ref = useRef<HTMLSpanElement>(null)\n const styleRef = useRef<HTMLStyleElement | null>(null)\n\n // Activity-Proof: toggle media attribute to disable styles synchronously\n // when hidden by <Activity>. On hide, cleanup sets media=\"not all\" before\n // paint so cursor styles don't leak into hidden containers.\n useLayoutEffect(() => {\n if (!styleRef.current) return\n styleRef.current.media = 'all'\n return () => {\n if (styleRef.current) styleRef.current.media = 'not all'\n }\n })\n\n // Portal-Proof: use ownerDocument to inject styles into the correct\n // document context (works in iframes, portals, and pop-out windows).\n useEffect(() => {\n const node = ref.current\n if (!node) return\n const doc = node.ownerDocument\n const win = doc.defaultView || window\n\n if (!hasPointerDevice(win)) return\n\n styleRef.current = injectCursorStyles(doc)\n\n const apply = () => {\n setCursorVariables(resolveColor(color, doc), doc)\n }\n apply()\n\n // Watch for theme attribute changes (CSS variable resolution)\n const observer = new MutationObserver(() => {\n if (color.startsWith('var(')) apply()\n })\n observer.observe(doc.documentElement, {\n attributes: true,\n attributeFilter: ['class', 'style', 'data-theme'],\n })\n\n win.addEventListener('themechange', apply)\n\n return () => {\n observer.disconnect()\n win.removeEventListener('themechange', apply)\n removeCursorStyles(doc)\n styleRef.current = null\n }\n }, [color])\n\n return <span ref={ref} style={{ display: 'none' }} />\n}\n\nexport default Aura\n","import { clearCursorCache } from '../core/cursors'\nimport {\n injectCursorStyles,\n setCursorVariables,\n removeCursorStyles,\n hasPointerDevice,\n} from '../core/apply'\n\nexport interface AuraOptions {\n /**\n * The shadow color for the cursor\n * @default '#000'\n */\n color?: string\n /**\n * The document to inject styles into. Defaults to the global document.\n * Portal-proof: pass a different document for iframes or pop-out windows.\n */\n document?: Document\n}\n\nlet currentColor: string | null = null\nlet currentDoc: Document | null = null\nlet observer: MutationObserver | null = null\nlet themeChangeHandler: (() => void) | null = null\n\n/**\n * Initialize Aura cursor shadows\n *\n * @example\n * ```js\n * Aura.init({ color: '#0C3EFF' })\n * Aura.setColor('#FF6183')\n * Aura.destroy()\n * ```\n */\nfunction init(options: AuraOptions = {}): void {\n if (typeof window === 'undefined') return\n\n const doc = options.document || document\n const win = doc.defaultView || window\n if (!hasPointerDevice(win)) return\n\n currentDoc = doc\n const color = options.color || '#000'\n\n injectCursorStyles(doc)\n applyColor(color)\n\n observer = new MutationObserver(() => {\n if (currentColor) applyColor(currentColor)\n })\n observer.observe(doc.documentElement, {\n attributes: true,\n attributeFilter: ['class', 'style', 'data-theme'],\n })\n\n themeChangeHandler = () => {\n if (currentColor) applyColor(currentColor)\n }\n win.addEventListener('themechange', themeChangeHandler)\n}\n\n/**\n * Update the cursor shadow color\n */\nfunction setColor(color: string): void {\n applyColor(color)\n}\n\n/**\n * Clean up Aura - removes styles, event listeners, and cache\n */\nfunction destroy(): void {\n const doc = currentDoc || document\n const win = doc.defaultView || window\n\n if (observer) {\n observer.disconnect()\n observer = null\n }\n if (themeChangeHandler) {\n win.removeEventListener('themechange', themeChangeHandler)\n themeChangeHandler = null\n }\n removeCursorStyles(doc)\n clearCursorCache()\n currentColor = null\n currentDoc = null\n}\n\nfunction applyColor(color: string): void {\n currentColor = color\n setCursorVariables(color, currentDoc || document)\n}\n\nexport const Aura = { init, setColor, destroy }\nexport default Aura\n"]}