@fab1o978/react-ui 0.2.0 → 0.2.2

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/ColorWheel/ColorWheel.module.scss"],"sourcesContent":["// Theme tokens are scoped to .root (component-local), not :root -- this\n// component must be safe to drop into an app with its own global theme\n// without colliding. All *computed* colors (the color you're picking, badge\n// tints, gradients) are passed in as inline styles from ColorWheel.tsx, not\n// CSS custom properties here -- only structural/theme tokens live in SCSS.\n\n// light/dark palettes -- identical values shared by every trigger below (OS\n// preference, host app's ambient theme, and this instance's own `theme` prop)\n@mixin light-palette {\n --bg: #ECEAE3;\n --surface: #FFFFFF;\n --surface-2: #E3E0D8;\n --border: #D2CDC0;\n --text: #1A1913;\n --text-dim: #726F64;\n --text-faint: #A8A398;\n --shadow-soft: 0 1px 2px rgba(30, 25, 15, 0.08);\n --check-a: #d8d4c8;\n --check-b: #f4f2ec;\n color-scheme: light;\n}\n@mixin dark-palette {\n --bg: #131217;\n --surface: #1C1B22;\n --surface-2: #26252E;\n --border: #34333D;\n --text: #ECEAF0;\n --text-dim: #8E8C99;\n --text-faint: #605E6B;\n --shadow-soft: 0 1px 2px rgba(0, 0, 0, 0.35);\n --check-a: #37353f;\n --check-b: #201f26;\n color-scheme: dark;\n}\n\n.root {\n @include light-palette;\n\n // theme=\"system\" (no data-theme of its own): fall back to the OS preference\n @media (prefers-color-scheme: dark) {\n &:not([data-theme='light']):not([data-theme='dark']) {\n @include dark-palette;\n }\n }\n\n // theme=\"system\": the host app's ambient theme (data-theme set on an\n // ancestor, e.g. <html> -- the same convention ColorPicker/Timeline read\n // from) takes precedence over the bare OS preference above when the app\n // declares one -- including explicitly overriding it back to light, since\n // the OS-preference rule above has no way to know the app disagrees\n :global([data-theme='light']) &:not([data-theme='light']):not([data-theme='dark']) {\n @include light-palette;\n }\n :global([data-theme='dark']) &:not([data-theme='light']):not([data-theme='dark']) {\n @include dark-palette;\n }\n\n // theme=\"dark\" / theme=\"light\": pinned explicitly on this instance, regardless of the OS or the app\n &[data-theme='dark'] {\n @include dark-palette;\n }\n &[data-theme='light'] {\n @include light-palette;\n }\n\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 20px;\n font-family: -apple-system, 'Segoe UI', Inter, 'Helvetica Neue', Arial, sans-serif;\n color: var(--text);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .root, .root *, .root *::before, .root *::after {\n animation-duration: 0.01ms !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n// ============ Recents (favorites) ============\n.recents {\n display: flex;\n align-items: center;\n gap: 7px;\n min-height: 30px;\n background: var(--surface-2);\n border-radius: 999px;\n padding: 5px 8px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.14), var(--shadow-soft);\n}\n\n.chipWrap {\n position: relative;\n flex: none;\n animation: chipIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) both;\n}\n\n.chip {\n width: 26px;\n height: 26px;\n border-radius: 50%;\n border: none;\n padding: 0;\n cursor: pointer;\n display: block;\n box-shadow: inset 0 0 0 1px rgba(128, 128, 128, 0.22), var(--shadow-soft);\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n\n &:hover {\n transform: scale(1.14) translateY(-1px);\n box-shadow: inset 0 0 0 1px rgba(128, 128, 128, 0.3), 0 4px 10px -3px rgba(0, 0, 0, 0.3);\n }\n &:active {\n transform: scale(1.02);\n }\n}\n\n// notification-badge style: sits off-center on the chip's rim, revealed only\n// on hover so it never competes with the chip's own click-to-select area\n.chipRemove {\n position: absolute;\n top: -3px;\n right: -3px;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n border: none;\n padding: 0;\n display: grid;\n place-items: center;\n background: var(--surface);\n color: var(--text-dim);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), inset 0 0 0 1px rgba(128, 128, 128, 0.25);\n cursor: pointer;\n z-index: 2;\n opacity: 0;\n pointer-events: none;\n transform: scale(0.6);\n transition: opacity 0.12s ease, transform 0.12s ease, color 0.12s ease;\n\n svg {\n width: 8px;\n height: 8px;\n }\n &:hover {\n color: var(--text);\n }\n .chipWrap:hover & {\n opacity: 1;\n pointer-events: auto;\n transform: scale(1);\n }\n}\n\n@keyframes chipIn {\n 0% { transform: scale(0) rotate(-25deg); opacity: 0; }\n 100% { transform: scale(1) rotate(0); opacity: 1; }\n}\n\n// ============ Picker: positioning context for the ring's bleed ============\n// Every direct child below is position:absolute (there's no backing card to\n// hold the box open), so .picker needs an explicit size or it measures as\n// 0x0 to the layout engine -- margin-top reserves room for what renders\n// above the shared center anchor (mostly the mode toggle), height reserves\n// what extends below it (the alpha arc).\n.picker {\n position: relative;\n margin-top: 82px;\n height: 265px;\n width: 272px;\n}\n\n.glow {\n position: absolute;\n width: 340px;\n height: 340px;\n left: 50%;\n top: 88px;\n transform: translate(-50%, -50%);\n border-radius: 50%;\n opacity: 0.55;\n pointer-events: none;\n z-index: 0;\n}\n\n// ============ Mode toggle: switches what the ring adjusts (H/S/V) ============\n.modeToggle {\n position: absolute;\n top: 88px;\n left: 50%;\n transform: translate(-50%, calc(-50% - 156px));\n z-index: 3;\n display: grid;\n // grid-template-columns and width are set inline (mode count is dynamic:\n // 3-way H/S/V or 4-way H/S/V/A depending on showAlphaControl)\n background: var(--surface-2);\n border-radius: 999px;\n padding: 3px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.14), var(--shadow-soft);\n}\n\n.modePill {\n position: absolute;\n top: 3px;\n bottom: 3px;\n left: 3px;\n // width is set inline (see .modeToggle)\n border-radius: 999px;\n background: var(--surface);\n box-shadow: var(--shadow-soft);\n transition: transform 0.25s cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n\n.modeButton {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n height: 22px;\n background: none;\n border: none;\n padding: 0;\n font-size: 10.5px;\n font-weight: 700;\n line-height: 22px;\n letter-spacing: 0.02em;\n color: var(--text-dim);\n cursor: pointer;\n transition: color 0.2s ease;\n\n &.active {\n color: var(--text);\n }\n &:hover:not(.active) {\n color: var(--text);\n }\n}\n\n// ============ Stage: a true ring (annulus via mask) ============\n.stage {\n position: absolute;\n top: -48px;\n left: 50%;\n width: 272px;\n height: 272px;\n transform: translateX(-50%);\n touch-action: none;\n}\n\n// shadow caster: a plain, unmasked circle behind the ring. box-shadow draws\n// outside its border-box regardless of the hole in the shape drawn on top of\n// it, so this reliably casts a shadow around the ring's outer edge --\n// filter:drop-shadow on the masked .ring itself is unreliable across engines.\n.stageShadow {\n position: absolute;\n inset: 0;\n border-radius: 50%;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.22), 0 10px 18px rgba(0, 0, 0, 0.22);\n pointer-events: none;\n}\n\n.ring {\n position: absolute;\n inset: 0;\n border-radius: 50%;\n pointer-events: none;\n z-index: 2;\n // background is set per-mode inline: hue spectrum / grey-to-color / black-to-color\n -webkit-mask: radial-gradient(circle closest-side, transparent 0 92px, black 93px 100%);\n mask: radial-gradient(circle closest-side, transparent 0 92px, black 93px 100%);\n}\n\n// rotated, not repositioned via top/left -- see the comment on\n// ringAngleFromTopDeg in ColorWheel.tsx for why\n.hueHandlePivot {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 0;\n height: 0;\n // `transform` creates a new stacking context, so this needs its own\n // z-index -- the child .hueHandle's z-index only ranks it within this\n // context, not against the ring/disc/badges sitting outside it\n z-index: 3;\n // strong ease-out -- fast start, long deceleration into the final angle,\n // like braking into position. Reads as a real sweep on a big mode-switch\n // jump, stays snappy on small wheel-tick nudges.\n transition: transform 0.32s cubic-bezier(0.16, 1, 0.3, 1);\n}\n.root[data-dragging='true'] .hueHandlePivot {\n transition: none;\n}\n.hueHandle {\n position: absolute;\n top: -114px; // mid-band radius (0.4191 * 272px stage), fixed distance from the pivot\n left: 0;\n width: 22px;\n height: 22px;\n border-radius: 50%;\n border: 3px solid #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(0, 0, 0, 0.15);\n transform: translate(-50%, -50%);\n cursor: grab;\n z-index: 3;\n}\n\n// ============ Alpha arc: a curved alpha slider outside the ring ============\n// a pure 1D control, position along the 120deg band (bottom-centered) fades\n// a checkerboard (alpha 0) into the current solid color (alpha 1). clip-path\n// also gates hit-testing, so clicks outside the visible crescent fall through.\n$arcPath: path('M 328.56,270 A 160 160 0 0 1 51.44,270 L 65.29,262 A 144 144 0 0 0 314.71,262 Z');\n\n// shadow caster: clip-path + filter:blur on the SAME element clips away the\n// blur's own soft edge (no room outside the path for it to fade into),\n// leaving a hard-edged smudge. Fix: blur a wrapper that ISN'T itself clipped\n// -- it composites its clipped child first, then blurs that whole result\n// freely, since nothing clips the wrapper afterward.\n.alphaArcShadowWrap {\n position: absolute;\n top: 88px;\n left: 50%;\n width: 380px;\n height: 380px;\n transform: translate(calc(-50% + 1px), calc(-50% + 5px));\n z-index: 1;\n pointer-events: none;\n filter: blur(7px);\n}\n.alphaArcShadow {\n position: absolute;\n inset: 0;\n background: rgba(0, 0, 0, 0.22);\n clip-path: $arcPath;\n}\n\n.alphaArc {\n position: absolute;\n top: 88px;\n left: 50%;\n width: 380px;\n height: 380px;\n transform: translate(-50%, -50%);\n touch-action: none;\n cursor: grab;\n z-index: 2;\n background: var(--surface-2);\n clip-path: $arcPath;\n}\n\n.alphaArcFill {\n position: absolute;\n inset: 0;\n // conic-gradient set inline (needs the live accent color)\n}\n\n// clip-path can't take a border-radius, so the band's two flat-cut ends are\n// \"rounded\" by capping them with plain circles sized to the band's own\n// thickness -- a pill cap, same trick as a rounded-end stroke. These sit\n// OUTSIDE .alphaArc (its clip-path would slice them too), positioned from\n// the shared center point like the mode toggle is.\n.alphaArcCap {\n position: absolute;\n top: 88px;\n left: 50%;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n z-index: 2;\n pointer-events: none;\n background: var(--surface-2);\n}\n.alphaArcCapStart {\n transform: translate(calc(-50% + 131.6px), calc(-50% + 76px));\n // background set inline (accent-solid, the \"full\" end)\n}\n.alphaArcCapEnd {\n transform: translate(calc(-50% - 131.6px), calc(-50% + 76px));\n}\n\n// sits OUTSIDE .alphaArc too, same reason as the caps -- clip-path would\n// slice it into a crescent whenever it nears the band's flat-cut ends\n.alphaArcHandle {\n position: absolute;\n top: 88px;\n left: 50%;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 2px solid #fff;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.2);\n z-index: 3;\n pointer-events: none;\n transition: transform 0.12s ease;\n}\n.root[data-dragging='true'] .alphaArcHandle {\n transition: none;\n}\n\n// ============ Current-color disc ============\n.currentDisc {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 156px;\n height: 156px;\n transform: translate(-50%, -50%);\n border-radius: 50%;\n overflow: hidden;\n cursor: pointer;\n z-index: 2;\n box-shadow: 0 10px 24px -8px rgba(20, 16, 10, 0.4), inset 0 0 0 1px rgba(0, 0, 0, 0.08);\n background-image:\n linear-gradient(45deg, var(--check-a) 25%, transparent 25%, transparent 75%, var(--check-a) 75%),\n linear-gradient(45deg, var(--check-a) 25%, transparent 25%, transparent 75%, var(--check-a) 75%);\n background-size: 12px 12px;\n background-position: 0 0, 6px 6px;\n background-color: var(--check-b);\n}\n\n.discFill {\n position: absolute;\n inset: 0;\n // background (rgba of current color, so the checkerboard reads through\n // when alpha < 1) set inline\n}\n\n.currentHex,\n.currentHexInput {\n position: absolute;\n inset: 0;\n z-index: 1;\n font-family: 'SF Mono', 'IBM Plex Mono', 'JetBrains Mono', Consolas, 'Liberation Mono', monospace;\n font-size: 17px;\n font-weight: 700;\n letter-spacing: 0.01em;\n font-variant-numeric: tabular-nums;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);\n // color set inline (computed for contrast against the current color)\n}\n.currentHex {\n display: grid;\n place-items: center;\n cursor: text;\n transition: transform 0.15s cubic-bezier(0.34, 1.56, 0.64, 1);\n\n &.copied {\n transform: scale(1.06);\n }\n}\n.currentHexInput {\n z-index: 2;\n width: 100%;\n height: 100%;\n text-align: center;\n background: transparent;\n border: none;\n outline: none;\n padding: 0;\n\n &::selection {\n background: rgba(255, 255, 255, 0.35);\n }\n}\n\n// badges resting inland on the disc, top (eyedropper) and bottom (save to\n// favorites) -- discreet: near-invisible fill, and instead of a drawn-on\n// border, an engraved groove (dark inset lip on top, faint highlight on the\n// bottom edge) so they read as carved into the disc rather than stuck on it\n.discBadge {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 34px;\n height: 34px;\n border-radius: 50%;\n border: none;\n display: grid;\n place-items: center;\n cursor: pointer;\n z-index: 3;\n transition: transform 0.15s ease, filter 0.15s ease;\n\n &:hover {\n filter: brightness(1.15);\n }\n svg {\n width: 15px;\n height: 15px;\n }\n}\n.discBadgeTop {\n transform: translate(-50%, calc(-50% - 46px));\n &:active {\n transform: translate(-50%, calc(-50% - 46px)) scale(0.92);\n }\n &.pulse {\n animation: badgePulseTop 0.4s ease;\n }\n}\n.discBadgeBottom {\n transform: translate(-50%, calc(-50% + 46px));\n &:active {\n transform: translate(-50%, calc(-50% + 46px)) scale(0.92);\n }\n}\n@keyframes badgePulseTop {\n 0% { transform: translate(-50%, calc(-50% - 46px)) scale(1); }\n 40% { transform: translate(-50%, calc(-50% - 46px)) scale(1.28); }\n 100% { transform: translate(-50%, calc(-50% - 46px)) scale(1); }\n}\n"],"mappings":"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","names":["root","recents","chipWrap","chip","chipRemove","chipIn","picker","glow","modeToggle","modePill","modeButton","active","stage","stageShadow","ring","hueHandlePivot","hueHandle","alphaArcShadowWrap","alphaArcShadow","alphaArc","alphaArcFill","alphaArcCap","alphaArcCapStart","alphaArcCapEnd","alphaArcHandle","currentDisc","discFill","currentHex","currentHexInput","copied","discBadge","discBadgeTop","pulse","discBadgeBottom","badgePulseTop"]}
1
+ {"version":3,"sources":["../../../src/components/ColorWheel/ColorWheel.module.scss"],"sourcesContent":["// Theme tokens are scoped to .root (component-local), not :root -- this\n// component must be safe to drop into an app with its own global theme\n// without colliding. All *computed* colors (the color you're picking, badge\n// tints, gradients) are passed in as inline styles from ColorWheel.tsx, not\n// CSS custom properties here -- only structural/theme tokens live in SCSS.\n\n// light/dark palettes -- identical values shared by every trigger below (OS\n// preference, host app's ambient theme, and this instance's own `theme` prop)\n@mixin light-palette {\n --bg: #ECEAE3;\n --surface: #FFFFFF;\n --surface-2: #E3E0D8;\n --border: #D2CDC0;\n --text: #1A1913;\n --text-dim: #726F64;\n --text-faint: #A8A398;\n --shadow-soft: 0 1px 2px rgba(30, 25, 15, 0.08);\n --check-a: #d8d4c8;\n --check-b: #f4f2ec;\n color-scheme: light;\n}\n@mixin dark-palette {\n --bg: #131217;\n --surface: #1C1B22;\n --surface-2: #26252E;\n --border: #34333D;\n --text: #ECEAF0;\n --text-dim: #8E8C99;\n --text-faint: #605E6B;\n --shadow-soft: 0 1px 2px rgba(0, 0, 0, 0.35);\n --check-a: #37353f;\n --check-b: #201f26;\n color-scheme: dark;\n}\n\n.root {\n @include light-palette;\n\n // theme=\"system\" (no data-theme of its own): fall back to the OS preference\n @media (prefers-color-scheme: dark) {\n &:not([data-theme='light']):not([data-theme='dark']) {\n @include dark-palette;\n }\n }\n\n // theme=\"system\": the host app's ambient theme (data-theme set on an\n // ancestor, e.g. <html> -- the same convention ColorPicker/Timeline read\n // from) takes precedence over the bare OS preference above when the app\n // declares one -- including explicitly overriding it back to light, since\n // the OS-preference rule above has no way to know the app disagrees\n :global([data-theme='light']) &:not([data-theme='light']):not([data-theme='dark']) {\n @include light-palette;\n }\n :global([data-theme='dark']) &:not([data-theme='light']):not([data-theme='dark']) {\n @include dark-palette;\n }\n\n // theme=\"dark\" / theme=\"light\": pinned explicitly on this instance, regardless of the OS or the app\n &[data-theme='dark'] {\n @include dark-palette;\n }\n &[data-theme='light'] {\n @include light-palette;\n }\n\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 20px;\n font-family: -apple-system, 'Segoe UI', Inter, 'Helvetica Neue', Arial, sans-serif;\n color: var(--text);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .root, .root *, .root *::before, .root *::after {\n animation-duration: 0.01ms !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n// ============ Recents (favorites) ============\n.recents {\n display: flex;\n align-items: center;\n gap: 7px;\n min-height: 30px;\n background: var(--surface-2);\n border-radius: 999px;\n padding: 5px 8px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.14), var(--shadow-soft);\n // `width` is set inline from ColorWheel.tsx (chip count * size + gaps) --\n // transitioning it turns an add/remove's shrink-to-fit resize into a\n // smooth resize instead of an instant snap\n transition: width 0.25s ease;\n}\n\n// same box (min-height + padding), just invisible -- keeps the slot's\n// footprint reserved so the rest of the layout doesn't shift when the last\n// preset is removed (or before the first one is ever added)\n.recentsEmpty {\n background: transparent;\n box-shadow: none;\n}\n\n.chipWrap {\n position: relative;\n flex: none;\n animation: chipIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) both;\n}\n\n// swaps in for .chipWrap while a chip is leaving (see removeFavorite /\n// handleChipRemoveEnd in ColorWheel.tsx) -- transform-only, so it keeps\n// occupying its flex slot (and .recents' width) until it's fully invisible,\n// at which point the actual removal + .recents' own width transition kick in\n.chipWrapRemoving {\n animation: chipOut 0.22s cubic-bezier(0.4, 0, 1, 1) both;\n pointer-events: none;\n}\n\n.chip {\n width: 26px;\n height: 26px;\n border-radius: 50%;\n border: none;\n padding: 0;\n cursor: pointer;\n display: block;\n box-shadow: inset 0 0 0 1px rgba(128, 128, 128, 0.22), var(--shadow-soft);\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n\n &:hover {\n transform: scale(1.14) translateY(-1px);\n box-shadow: inset 0 0 0 1px rgba(128, 128, 128, 0.3), 0 4px 10px -3px rgba(0, 0, 0, 0.3);\n }\n &:active {\n transform: scale(1.02);\n }\n}\n\n// notification-badge style: sits off-center on the chip's rim, revealed only\n// on hover so it never competes with the chip's own click-to-select area\n.chipRemove {\n position: absolute;\n top: -3px;\n right: -3px;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n border: none;\n padding: 0;\n display: grid;\n place-items: center;\n background: var(--surface);\n color: var(--text-dim);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), inset 0 0 0 1px rgba(128, 128, 128, 0.25);\n cursor: pointer;\n z-index: 2;\n opacity: 0;\n pointer-events: none;\n transform: scale(0.6);\n transition: opacity 0.12s ease, transform 0.12s ease, color 0.12s ease;\n\n svg {\n width: 8px;\n height: 8px;\n }\n &:hover {\n color: var(--text);\n }\n .chipWrap:hover & {\n opacity: 1;\n pointer-events: auto;\n transform: scale(1);\n }\n}\n\n@keyframes chipIn {\n 0% { transform: scale(0) rotate(-25deg); opacity: 0; }\n 100% { transform: scale(1) rotate(0); opacity: 1; }\n}\n\n@keyframes chipOut {\n 0% { transform: scale(1) rotate(0); opacity: 1; }\n 100% { transform: scale(0) rotate(18deg); opacity: 0; }\n}\n\n// ============ Picker: positioning context for the ring's bleed ============\n// Every direct child below is position:absolute (there's no backing card to\n// hold the box open), so .picker needs an explicit size or it measures as\n// 0x0 to the layout engine -- margin-top reserves room for what renders\n// above the shared center anchor (mostly the mode toggle). `height` is set\n// inline from ColorWheel.tsx instead of here, since how far down it needs to\n// reserve depends on `arcVisible` (the alpha arc reaches lower than the ring\n// alone does) -- plain SCSS can't see that prop.\n.picker {\n position: relative;\n margin-top: 96px;\n width: 272px;\n}\n\n.glow {\n position: absolute;\n width: 340px;\n height: 340px;\n left: 50%;\n top: 88px;\n transform: translate(-50%, -50%);\n border-radius: 50%;\n opacity: 0.55;\n pointer-events: none;\n z-index: 0;\n}\n\n// ============ Mode toggle: switches what the ring adjusts (H/S/V) ============\n.modeToggle {\n position: absolute;\n top: 88px;\n left: 50%;\n transform: translate(-50%, calc(-50% - 170px));\n z-index: 3;\n display: grid;\n // grid-template-columns and width are set inline (mode count is dynamic:\n // 3-way H/S/V or 4-way H/S/V/A depending on showAlphaControl)\n background: var(--surface-2);\n border-radius: 999px;\n padding: 3px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.14), var(--shadow-soft);\n}\n\n.modePill {\n position: absolute;\n top: 3px;\n bottom: 3px;\n left: 3px;\n // width is set inline (see .modeToggle)\n border-radius: 999px;\n background: var(--surface);\n box-shadow: var(--shadow-soft);\n transition: transform 0.25s cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n\n.modeButton {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n height: 22px;\n background: none;\n border: none;\n padding: 0;\n font-size: 10.5px;\n font-weight: 700;\n line-height: 22px;\n letter-spacing: 0.02em;\n color: var(--text-dim);\n cursor: pointer;\n transition: color 0.2s ease;\n\n &.active {\n color: var(--text);\n }\n &:hover:not(.active) {\n color: var(--text);\n }\n}\n\n// ============ Stage: a true ring (annulus via mask) ============\n.stage {\n position: absolute;\n top: -48px;\n left: 50%;\n width: 272px;\n height: 272px;\n transform: translateX(-50%);\n touch-action: none;\n}\n\n// shadow caster: a plain, unmasked circle behind the ring. box-shadow draws\n// outside its border-box regardless of the hole in the shape drawn on top of\n// it, so this reliably casts a shadow around the ring's outer edge --\n// filter:drop-shadow on the masked .ring itself is unreliable across engines.\n.stageShadow {\n position: absolute;\n inset: 0;\n border-radius: 50%;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.22), 0 10px 18px rgba(0, 0, 0, 0.22);\n pointer-events: none;\n}\n\n.ring {\n position: absolute;\n inset: 0;\n border-radius: 50%;\n pointer-events: none;\n z-index: 2;\n // background is set per-mode inline: hue spectrum / grey-to-color / black-to-color\n -webkit-mask: radial-gradient(circle closest-side, transparent 0 92px, black 93px 100%);\n mask: radial-gradient(circle closest-side, transparent 0 92px, black 93px 100%);\n}\n\n// rotated, not repositioned via top/left -- see the comment on\n// ringAngleFromTopDeg in ColorWheel.tsx for why\n.hueHandlePivot {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 0;\n height: 0;\n // `transform` creates a new stacking context, so this needs its own\n // z-index -- the child .hueHandle's z-index only ranks it within this\n // context, not against the ring/disc/badges sitting outside it\n z-index: 3;\n // strong ease-out -- fast start, long deceleration into the final angle,\n // like braking into position. Reads as a real sweep on a big mode-switch\n // jump, stays snappy on small wheel-tick nudges.\n transition: transform 0.32s cubic-bezier(0.16, 1, 0.3, 1);\n}\n.root[data-dragging='true'] .hueHandlePivot {\n transition: none;\n}\n.hueHandle {\n position: absolute;\n top: -114px; // mid-band radius (0.4191 * 272px stage), fixed distance from the pivot\n left: 0;\n width: 22px;\n height: 22px;\n border-radius: 50%;\n border: 3px solid #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(0, 0, 0, 0.15);\n transform: translate(-50%, -50%);\n cursor: grab;\n z-index: 3;\n}\n\n// ============ Alpha arc: a curved alpha slider outside the ring ============\n// a pure 1D control, position along the 120deg band (bottom-centered) fades\n// a checkerboard (alpha 0) into the current solid color (alpha 1). clip-path\n// also gates hit-testing, so clicks outside the visible crescent fall through.\n$arcPath: path('M 328.56,270 A 160 160 0 0 1 51.44,270 L 65.29,262 A 144 144 0 0 0 314.71,262 Z');\n\n// shadow caster: clip-path + filter:blur on the SAME element clips away the\n// blur's own soft edge (no room outside the path for it to fade into),\n// leaving a hard-edged smudge. Fix: blur a wrapper that ISN'T itself clipped\n// -- it composites its clipped child first, then blurs that whole result\n// freely, since nothing clips the wrapper afterward.\n.alphaArcShadowWrap {\n position: absolute;\n top: 88px;\n left: 50%;\n width: 380px;\n height: 380px;\n transform: translate(calc(-50% + 1px), calc(-50% + 5px));\n z-index: 1;\n pointer-events: none;\n filter: blur(7px);\n}\n.alphaArcShadow {\n position: absolute;\n inset: 0;\n background: rgba(0, 0, 0, 0.22);\n clip-path: $arcPath;\n}\n\n.alphaArc {\n position: absolute;\n top: 88px;\n left: 50%;\n width: 380px;\n height: 380px;\n transform: translate(-50%, -50%);\n touch-action: none;\n cursor: grab;\n z-index: 2;\n background: var(--surface-2);\n clip-path: $arcPath;\n}\n\n.alphaArcFill {\n position: absolute;\n inset: 0;\n // conic-gradient set inline (needs the live accent color)\n}\n\n// clip-path can't take a border-radius, so the band's two flat-cut ends are\n// \"rounded\" by capping them with plain circles sized to the band's own\n// thickness -- a pill cap, same trick as a rounded-end stroke. These sit\n// OUTSIDE .alphaArc (its clip-path would slice them too), positioned from\n// the shared center point like the mode toggle is.\n.alphaArcCap {\n position: absolute;\n top: 88px;\n left: 50%;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n z-index: 2;\n pointer-events: none;\n background: var(--surface-2);\n}\n.alphaArcCapStart {\n transform: translate(calc(-50% + 131.6px), calc(-50% + 76px));\n // background set inline (accent-solid, the \"full\" end)\n}\n.alphaArcCapEnd {\n transform: translate(calc(-50% - 131.6px), calc(-50% + 76px));\n}\n\n// sits OUTSIDE .alphaArc too, same reason as the caps -- clip-path would\n// slice it into a crescent whenever it nears the band's flat-cut ends\n.alphaArcHandle {\n position: absolute;\n top: 88px;\n left: 50%;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 2px solid #fff;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.2);\n z-index: 3;\n pointer-events: none;\n transition: transform 0.12s ease;\n}\n.root[data-dragging='true'] .alphaArcHandle {\n transition: none;\n}\n\n// ============ Current-color disc ============\n.currentDisc {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 156px;\n height: 156px;\n transform: translate(-50%, -50%);\n border-radius: 50%;\n overflow: hidden;\n cursor: pointer;\n z-index: 2;\n box-shadow: 0 10px 24px -8px rgba(20, 16, 10, 0.4), inset 0 0 0 1px rgba(0, 0, 0, 0.08);\n background-image:\n linear-gradient(45deg, var(--check-a) 25%, transparent 25%, transparent 75%, var(--check-a) 75%),\n linear-gradient(45deg, var(--check-a) 25%, transparent 25%, transparent 75%, var(--check-a) 75%);\n background-size: 12px 12px;\n background-position: 0 0, 6px 6px;\n background-color: var(--check-b);\n}\n\n.discFill {\n position: absolute;\n inset: 0;\n // background (rgba of current color, so the checkerboard reads through\n // when alpha < 1) set inline\n}\n\n.currentHex,\n.currentHexInput {\n position: absolute;\n inset: 0;\n z-index: 1;\n font-family: 'SF Mono', 'IBM Plex Mono', 'JetBrains Mono', Consolas, 'Liberation Mono', monospace;\n font-size: 17px;\n font-weight: 700;\n letter-spacing: 0.01em;\n font-variant-numeric: tabular-nums;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);\n // color set inline (computed for contrast against the current color)\n}\n.currentHex {\n display: grid;\n place-items: center;\n cursor: text;\n transition: transform 0.15s cubic-bezier(0.34, 1.56, 0.64, 1);\n\n &.copied {\n transform: scale(1.06);\n }\n}\n.currentHexInput {\n z-index: 2;\n width: 100%;\n height: 100%;\n text-align: center;\n background: transparent;\n border: none;\n outline: none;\n padding: 0;\n\n &::selection {\n background: rgba(255, 255, 255, 0.35);\n }\n}\n\n// badges resting inland on the disc, top (eyedropper) and bottom (save to\n// favorites) -- discreet: near-invisible fill, and instead of a drawn-on\n// border, an engraved groove (dark inset lip on top, faint highlight on the\n// bottom edge) so they read as carved into the disc rather than stuck on it\n.discBadge {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 34px;\n height: 34px;\n border-radius: 50%;\n border: none;\n display: grid;\n place-items: center;\n cursor: pointer;\n z-index: 3;\n transition: transform 0.15s ease, filter 0.15s ease;\n\n &:hover {\n filter: brightness(1.15);\n }\n svg {\n width: 15px;\n height: 15px;\n }\n}\n.discBadgeTop {\n transform: translate(-50%, calc(-50% - 46px));\n &:active {\n transform: translate(-50%, calc(-50% - 46px)) scale(0.92);\n }\n &.pulse {\n animation: badgePulseTop 0.4s ease;\n }\n}\n.discBadgeBottom {\n transform: translate(-50%, calc(-50% + 46px));\n &:active {\n transform: translate(-50%, calc(-50% + 46px)) scale(0.92);\n }\n}\n@keyframes badgePulseTop {\n 0% { transform: translate(-50%, calc(-50% - 46px)) scale(1); }\n 40% { transform: translate(-50%, calc(-50% - 46px)) scale(1.28); }\n 100% { transform: translate(-50%, calc(-50% - 46px)) scale(1); }\n}\n"],"mappings":"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","names":["root","recents","recentsEmpty","chipWrap","chipWrapRemoving","chip","chipRemove","chipIn","chipOut","picker","glow","modeToggle","modePill","modeButton","active","stage","stageShadow","ring","hueHandlePivot","hueHandle","alphaArcShadowWrap","alphaArcShadow","alphaArc","alphaArcFill","alphaArcCap","alphaArcCapStart","alphaArcCapEnd","alphaArcHandle","currentDisc","discFill","currentHex","currentHexInput","copied","discBadge","discBadgeTop","pulse","discBadgeBottom","badgePulseTop"]}
@@ -7,7 +7,9 @@ import { jsxs, jsx } from 'react/jsx-runtime';
7
7
  var ColorWheel_module_default = {
8
8
  root: "ColorWheel_module_root2",
9
9
  recents: "ColorWheel_module_recents2",
10
+ recentsEmpty: "ColorWheel_module_recentsEmpty2",
10
11
  chipWrap: "ColorWheel_module_chipWrap2",
12
+ chipWrapRemoving: "ColorWheel_module_chipWrapRemoving2",
11
13
  chip: "ColorWheel_module_chip2",
12
14
  chipRemove: "ColorWheel_module_chipRemove2",
13
15
  picker: "ColorWheel_module_picker2",
@@ -264,6 +266,13 @@ var RING_OUTER_FRAC = 0.5;
264
266
  var ARC_A0 = 30;
265
267
  var ARC_A1 = 150;
266
268
  var ARC_HANDLE_R_FRAC = 152 / 380;
269
+ var PICKER_HEIGHT_WITH_ARC = 265;
270
+ var PICKER_HEIGHT_NO_ARC = 224;
271
+ var CHIP_SIZE = 26;
272
+ var CHIP_GAP = 7;
273
+ function recentsContentWidth(chipCount) {
274
+ return chipCount > 0 ? chipCount * CHIP_SIZE + (chipCount - 1) * CHIP_GAP : 0;
275
+ }
267
276
  var MODES_HSV = ["h", "s", "v"];
268
277
  var MODES_HSVA = ["h", "s", "v", "a"];
269
278
  function ringGradient(mode, hsv) {
@@ -309,6 +318,15 @@ function ColorWheel({
309
318
  const [editing, setEditing] = useState(false);
310
319
  const [editValue, setEditValue] = useState("");
311
320
  const [eyedropperSupported, setEyedropperSupported] = useState(false);
321
+ const [removingHexes, setRemovingHexes] = useState(/* @__PURE__ */ new Set());
322
+ const [recentsGrown, setRecentsGrown] = useState(false);
323
+ const recentsGrowRaf = useRef(0);
324
+ useEffect(() => {
325
+ recentsGrowRaf.current = requestAnimationFrame(() => {
326
+ recentsGrowRaf.current = requestAnimationFrame(() => setRecentsGrown(true));
327
+ });
328
+ return () => cancelAnimationFrame(recentsGrowRaf.current);
329
+ }, []);
312
330
  const accentVars = accent ? accentToCssVars(deriveAccent(accent), "colorwheel") : {};
313
331
  const lastEmitted = useRef(value);
314
332
  useEffect(() => {
@@ -504,6 +522,15 @@ function ColorWheel({
504
522
  if (next) commit(next.hsv, next.a);
505
523
  }
506
524
  function removeFavorite(hex) {
525
+ setRemovingHexes((prev) => new Set(prev).add(hex));
526
+ }
527
+ function handleChipRemoveEnd(hex) {
528
+ setRemovingHexes((prev) => {
529
+ if (!prev.has(hex)) return prev;
530
+ const next = new Set(prev);
531
+ next.delete(hex);
532
+ return next;
533
+ });
507
534
  onFavoritesChange?.(favorites.filter((h) => h !== hex));
508
535
  }
509
536
  return /* @__PURE__ */ jsxs(
@@ -517,33 +544,57 @@ function ColorWheel({
517
544
  ...size !== 1 ? { transform: `scale(${size})`, transformOrigin: "top center" } : void 0
518
545
  },
519
546
  children: [
520
- favorites.length > 0 && /* @__PURE__ */ jsx("div", { className: ColorWheel_module_default.recents, children: favorites.map((hex, i) => /* @__PURE__ */ jsxs("div", { className: ColorWheel_module_default.chipWrap, style: { animationDelay: `${i * 0.02}s` }, children: [
521
- /* @__PURE__ */ jsx(
522
- "button",
523
- {
524
- type: "button",
525
- className: ColorWheel_module_default.chip,
526
- style: { background: hex.length > 7 ? hex.slice(0, 7) : hex },
527
- title: hex,
528
- "aria-label": `Apply color ${hex}`,
529
- onClick: () => applyFavorite(hex)
530
- }
531
- ),
532
- /* @__PURE__ */ jsx(
533
- "button",
534
- {
535
- type: "button",
536
- className: ColorWheel_module_default.chipRemove,
537
- "aria-label": `Remove ${hex} from favorites`,
538
- onClick: (e) => {
539
- e.stopPropagation();
540
- removeFavorite(hex);
541
- },
542
- children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 3, strokeLinecap: "round", children: /* @__PURE__ */ jsx("path", { d: "M6 6l12 12M18 6L6 18" }) })
543
- }
544
- )
545
- ] }, hex + i)) }),
546
- /* @__PURE__ */ jsxs("div", { className: ColorWheel_module_default.picker, children: [
547
+ (favorites.length > 0 || onFavoritesChange) && /* @__PURE__ */ jsx(
548
+ "div",
549
+ {
550
+ className: [ColorWheel_module_default.recents, favorites.length === 0 ? ColorWheel_module_default.recentsEmpty : ""].join(" "),
551
+ style: { width: recentsGrown ? recentsContentWidth(favorites.length) : 0 },
552
+ children: favorites.map((hex, i) => (
553
+ // keyed by hex alone (not index) so an add/remove -- which
554
+ // shifts every other item's index -- doesn't remount and replay
555
+ // the entrance animation on chips that were already there; only
556
+ // a genuinely new hex mounts fresh and animates in
557
+ /* @__PURE__ */ jsxs(
558
+ "div",
559
+ {
560
+ className: [ColorWheel_module_default.chipWrap, removingHexes.has(hex) ? ColorWheel_module_default.chipWrapRemoving : ""].join(" "),
561
+ style: { animationDelay: removingHexes.has(hex) ? void 0 : `${i * 0.05}s` },
562
+ onAnimationEnd: (e) => {
563
+ if (e.target === e.currentTarget && e.animationName.includes("chipOut")) handleChipRemoveEnd(hex);
564
+ },
565
+ children: [
566
+ /* @__PURE__ */ jsx(
567
+ "button",
568
+ {
569
+ type: "button",
570
+ className: ColorWheel_module_default.chip,
571
+ style: { background: hex.length > 7 ? hex.slice(0, 7) : hex },
572
+ title: hex,
573
+ "aria-label": `Apply color ${hex}`,
574
+ onClick: () => applyFavorite(hex)
575
+ }
576
+ ),
577
+ /* @__PURE__ */ jsx(
578
+ "button",
579
+ {
580
+ type: "button",
581
+ className: ColorWheel_module_default.chipRemove,
582
+ "aria-label": `Remove ${hex} from favorites`,
583
+ onClick: (e) => {
584
+ e.stopPropagation();
585
+ removeFavorite(hex);
586
+ },
587
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 3, strokeLinecap: "round", children: /* @__PURE__ */ jsx("path", { d: "M6 6l12 12M18 6L6 18" }) })
588
+ }
589
+ )
590
+ ]
591
+ },
592
+ hex
593
+ )
594
+ ))
595
+ }
596
+ ),
597
+ /* @__PURE__ */ jsxs("div", { className: ColorWheel_module_default.picker, style: { height: arcVisible ? PICKER_HEIGHT_WITH_ARC : PICKER_HEIGHT_NO_ARC }, children: [
547
598
  /* @__PURE__ */ jsx(
548
599
  "div",
549
600
  {