@zag-js/color-picker 0.53.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,2 +1,1406 @@
1
- import{createAnatomy}from"@zag-js/anatomy";var anatomy=createAnatomy("color-picker",["root","label","control","trigger","positioner","content","area","areaThumb","areaBackground","channelSlider","channelSliderTrack","channelSliderThumb","channelInput","transparencyGrid","swatchGroup","swatchTrigger","swatchIndicator","swatch","eyeDropperTrigger","formatTrigger","formatSelect"]);var parts=anatomy.build();import{getColorAreaGradient,normalizeColor}from"@zag-js/color-utils";import{getEventKey,getEventPoint,getEventStep,isLeftClick,isModifierKey}from"@zag-js/dom-event";import{dataAttr,query,visuallyHiddenStyle}from"@zag-js/dom-query";import{getPlacementStyles}from"@zag-js/popper";import{getRelativePoint}from"@zag-js/dom-event";import{createScope,queryAll}from"@zag-js/dom-query";var dom=createScope({getRootId:ctx=>ctx.ids?.root??`color-picker:${ctx.id}`,getLabelId:ctx=>ctx.ids?.label??`color-picker:${ctx.id}:label`,getHiddenInputId:ctx=>`color-picker:${ctx.id}:hidden-input`,getControlId:ctx=>ctx.ids?.control??`color-picker:${ctx.id}:control`,getTriggerId:ctx=>ctx.ids?.trigger??`color-picker:${ctx.id}:trigger`,getContentId:ctx=>ctx.ids?.content??`color-picker:${ctx.id}:content`,getPositionerId:ctx=>`color-picker:${ctx.id}:positioner`,getFormatSelectId:ctx=>`color-picker:${ctx.id}:format-select`,getAreaId:ctx=>ctx.ids?.area??`color-picker:${ctx.id}:area`,getAreaGradientId:ctx=>ctx.ids?.areaGradient??`color-picker:${ctx.id}:area-gradient`,getAreaThumbId:ctx=>ctx.ids?.areaThumb??`color-picker:${ctx.id}:area-thumb`,getChannelSliderId:(ctx,channel)=>ctx.ids?.channelSliderTrack?.(channel)??`color-picker:${ctx.id}:slider-track:${channel}`,getChannelSliderThumbId:(ctx,channel)=>ctx.ids?.channelSliderThumb?.(channel)??`color-picker:${ctx.id}:slider-thumb:${channel}`,getContentEl:ctx=>dom.getById(ctx,dom.getContentId(ctx)),getAreaThumbEl:ctx=>dom.getById(ctx,dom.getAreaThumbId(ctx)),getChannelSliderThumbEl:(ctx,channel)=>dom.getById(ctx,dom.getChannelSliderThumbId(ctx,channel)),getChannelInputEl:(ctx,channel)=>{return[...queryAll(dom.getContentEl(ctx),`input[data-channel="${channel}"]`),...queryAll(dom.getControlEl(ctx),`input[data-channel="${channel}"]`)]},getFormatSelectEl:ctx=>dom.getById(ctx,dom.getFormatSelectId(ctx)),getHiddenInputEl:ctx=>dom.getById(ctx,dom.getHiddenInputId(ctx)),getAreaEl:ctx=>dom.getById(ctx,dom.getAreaId(ctx)),getAreaValueFromPoint(ctx,point){const areaEl=dom.getAreaEl(ctx);if(!areaEl)return;const{percent}=getRelativePoint(point,areaEl);return percent},getControlEl:ctx=>dom.getById(ctx,dom.getControlId(ctx)),getTriggerEl:ctx=>dom.getById(ctx,dom.getTriggerId(ctx)),getPositionerEl:ctx=>dom.getById(ctx,dom.getPositionerId(ctx)),getChannelSliderTrackEl:(ctx,channel)=>{return dom.getById(ctx,dom.getChannelSliderId(ctx,channel))},getChannelSliderValueFromPoint(ctx,point,channel){const trackEl=dom.getChannelSliderTrackEl(ctx,channel);if(!trackEl)return;const{percent}=getRelativePoint(point,trackEl);return percent},getChannelInputEls:ctx=>{return[...queryAll(dom.getContentEl(ctx),"input[data-channel]"),...queryAll(dom.getControlEl(ctx),"input[data-channel]")]}});import{parseColor}from"@zag-js/color-utils";function getChannelDisplayColor(color,channel){switch(channel){case"hue":return parseColor(`hsl(${color.getChannelValue("hue")}, 100%, 50%)`);case"lightness":case"brightness":case"saturation":case"red":case"green":case"blue":return color.withChannelValue("alpha",1);case"alpha":{return color}default:throw new Error("Unknown color channel: "+channel)}}import{parseColor as parseColor2}from"@zag-js/color-utils";function getChannelValue(color,channel){if(channel==null)return"";if(channel==="hex"){return color.toString("hex")}if(channel==="css"){return color.toString("css")}if(channel in color){return color.getChannelValue(channel).toString()}const isHSL=color.getFormat()==="hsla";switch(channel){case"hue":return isHSL?color.toFormat("hsla").getChannelValue("hue").toString():color.toFormat("hsba").getChannelValue("hue").toString();case"saturation":return isHSL?color.toFormat("hsla").getChannelValue("saturation").toString():color.toFormat("hsba").getChannelValue("saturation").toString();case"lightness":return color.toFormat("hsla").getChannelValue("lightness").toString();case"brightness":return color.toFormat("hsba").getChannelValue("brightness").toString();case"red":case"green":case"blue":return color.toFormat("rgba").getChannelValue(channel).toString();default:return color.getChannelValue(channel).toString()}}function getChannelRange(color,channel){switch(channel){case"hex":const minColor=parseColor2("#000000");const maxColor=parseColor2("#FFFFFF");return{minValue:minColor.toHexInt(),maxValue:maxColor.toHexInt(),pageSize:10,step:1};case"css":return void 0;case"hue":case"saturation":case"lightness":return color.toFormat("hsla").getChannelRange(channel);case"brightness":return color.toFormat("hsba").getChannelRange(channel);case"red":case"green":case"blue":return color.toFormat("rgba").getChannelRange(channel);default:return color.getChannelRange(channel)}}function getSliderBackgroundDirection(orientation,dir){if(orientation==="vertical"){return"top"}else if(dir==="ltr"){return"right"}else{return"left"}}var getSliderBackground=props=>{const{channel,value,dir}=props;const bgDirection=getSliderBackgroundDirection(props.orientation,dir);const{minValue,maxValue}=value.getChannelRange(channel);switch(channel){case"hue":return`linear-gradient(to ${bgDirection}, rgb(255, 0, 0) 0%, rgb(255, 255, 0) 17%, rgb(0, 255, 0) 33%, rgb(0, 255, 255) 50%, rgb(0, 0, 255) 67%, rgb(255, 0, 255) 83%, rgb(255, 0, 0) 100%)`;case"lightness":{let start=value.withChannelValue(channel,minValue).toString("css");let middle=value.withChannelValue(channel,(maxValue-minValue)/2).toString("css");let end=value.withChannelValue(channel,maxValue).toString("css");return`linear-gradient(to ${bgDirection}, ${start}, ${middle}, ${end})`}case"saturation":case"brightness":case"red":case"green":case"blue":case"alpha":{let start=value.withChannelValue(channel,minValue).toString("css");let end=value.withChannelValue(channel,maxValue).toString("css");return`linear-gradient(to ${bgDirection}, ${start}, ${end})`}default:throw new Error("Unknown color channel: "+channel)}};function connect(state,send,normalize){const value=state.context.value;const areaValue=state.context.areaValue;const valueAsString=state.context.valueAsString;const disabled=state.context.isDisabled;const interactive=state.context.isInteractive;const dragging=state.hasTag("dragging");const open=state.hasTag("open");const focused=state.hasTag("focused");const getAreaChannels=props=>{const channels=areaValue.getChannels();return{xChannel:props.xChannel??channels[1],yChannel:props.yChannel??channels[2]}};const currentPlacement=state.context.currentPlacement;const popperStyles=getPlacementStyles({...state.context.positioning,placement:currentPlacement});function getSwatchTriggerState(props){const color=normalizeColor(props.value).toFormat(state.context.format);return{value:color,valueAsString:color.toString("hex"),checked:color.isEqual(value),disabled:props.disabled||!interactive}}return{dragging,open,valueAsString,value,setOpen(nextOpen){if(nextOpen===open)return;send({type:nextOpen?"OPEN":"CLOSE"})},setValue(value2){send({type:"VALUE.SET",value:normalizeColor(value2),src:"set-color"})},getChannelValue(channel){return getChannelValue(value,channel)},setChannelValue(channel,channelValue){const color=value.withChannelValue(channel,channelValue);send({type:"VALUE.SET",value:color,src:"set-channel"})},format:state.context.format,setFormat(format){const formatValue=value.toFormat(format);send({type:"VALUE.SET",value:formatValue,src:"set-format"})},alpha:value.getChannelValue("alpha"),setAlpha(alphaValue){const color=value.withChannelValue("alpha",alphaValue);send({type:"VALUE.SET",value:color,src:"set-alpha"})},rootProps:normalize.element({...parts.root.attrs,dir:state.context.dir,id:dom.getRootId(state.context),"data-disabled":dataAttr(disabled),"data-readonly":dataAttr(state.context.readOnly),style:{"--value":value.toString("css")}}),labelProps:normalize.element({...parts.label.attrs,dir:state.context.dir,id:dom.getLabelId(state.context),htmlFor:dom.getHiddenInputId(state.context),"data-disabled":dataAttr(disabled),"data-readonly":dataAttr(state.context.readOnly),"data-focus":dataAttr(focused),onClick(event){event.preventDefault();const inputEl=query(dom.getControlEl(state.context),"[data-channel=hex]");inputEl?.focus({preventScroll:true})}}),controlProps:normalize.element({...parts.control.attrs,id:dom.getControlId(state.context),dir:state.context.dir,"data-disabled":dataAttr(disabled),"data-readonly":dataAttr(state.context.readOnly),"data-state":open?"open":"closed","data-focus":dataAttr(focused)}),triggerProps:normalize.button({...parts.trigger.attrs,id:dom.getTriggerId(state.context),dir:state.context.dir,disabled,"aria-label":`select color. current color is ${valueAsString}`,"aria-controls":dom.getContentId(state.context),"aria-labelledby":dom.getLabelId(state.context),"data-disabled":dataAttr(disabled),"data-readonly":dataAttr(state.context.readOnly),"data-placement":currentPlacement,"aria-expanded":dataAttr(open),"data-state":open?"open":"closed","data-focus":dataAttr(focused),type:"button",onClick(){if(!interactive)return;send({type:"TRIGGER.CLICK"})},onBlur(){if(!interactive)return;send({type:"TRIGGER.BLUR"})},style:{position:"relative"}}),positionerProps:normalize.element({...parts.positioner.attrs,id:dom.getPositionerId(state.context),dir:state.context.dir,style:popperStyles.floating}),contentProps:normalize.element({...parts.content.attrs,id:dom.getContentId(state.context),dir:state.context.dir,"data-placement":currentPlacement,"data-state":open?"open":"closed",hidden:!open}),getAreaProps(props={}){const{xChannel,yChannel}=getAreaChannels(props);const{areaStyles}=getColorAreaGradient(areaValue,{xChannel,yChannel,dir:state.context.dir});return normalize.element({...parts.area.attrs,id:dom.getAreaId(state.context),role:"group",onPointerDown(event){if(!interactive)return;if(!isLeftClick(event))return;if(isModifierKey(event))return;const point=getEventPoint(event);const channel={xChannel,yChannel};send({type:"AREA.POINTER_DOWN",point,channel,id:"area"});event.preventDefault()},style:{position:"relative",touchAction:"none",forcedColorAdjust:"none",...areaStyles}})},getAreaBackgroundProps(props={}){const{xChannel,yChannel}=getAreaChannels(props);const{areaGradientStyles}=getColorAreaGradient(areaValue,{xChannel,yChannel,dir:state.context.dir});return normalize.element({...parts.areaBackground.attrs,id:dom.getAreaGradientId(state.context),style:{position:"relative",touchAction:"none",forcedColorAdjust:"none",...areaGradientStyles}})},getAreaThumbProps(props={}){const{xChannel,yChannel}=getAreaChannels(props);const channel={xChannel,yChannel};const xPercent=areaValue.getChannelValuePercent(xChannel);const yPercent=1-areaValue.getChannelValuePercent(yChannel);const xValue=areaValue.getChannelValue(xChannel);const yValue=areaValue.getChannelValue(yChannel);return normalize.element({...parts.areaThumb.attrs,id:dom.getAreaThumbId(state.context),dir:state.context.dir,tabIndex:disabled?void 0:0,"data-disabled":dataAttr(disabled),role:"slider","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":xValue,"aria-label":`${xChannel} and ${yChannel}`,"aria-roledescription":"2d slider","aria-valuetext":`${xChannel} ${xValue}, ${yChannel} ${yValue}`,style:{position:"absolute",left:`${xPercent*100}%`,top:`${yPercent*100}%`,transform:"translate(-50%, -50%)",touchAction:"none",forcedColorAdjust:"none",background:areaValue.withChannelValue("alpha",1).toString("css")},onFocus(){if(!interactive)return;send({type:"AREA.FOCUS",id:"area",channel})},onKeyDown(event){if(event.defaultPrevented)return;if(!interactive)return;const step=getEventStep(event);const keyMap={ArrowUp(){send({type:"AREA.ARROW_UP",channel,step})},ArrowDown(){send({type:"AREA.ARROW_DOWN",channel,step})},ArrowLeft(){send({type:"AREA.ARROW_LEFT",channel,step})},ArrowRight(){send({type:"AREA.ARROW_RIGHT",channel,step})},PageUp(){send({type:"AREA.PAGE_UP",channel,step})},PageDown(){send({type:"AREA.PAGE_DOWN",channel,step})},Escape(event2){event2.stopPropagation()}};const exec=keyMap[getEventKey(event,state.context)];if(exec){exec(event);event.preventDefault()}}})},getTransparencyGridProps(props={}){const{size="12px"}=props;return normalize.element({...parts.transparencyGrid.attrs,style:{"--size":size,width:"100%",height:"100%",position:"absolute",backgroundColor:"#fff",backgroundImage:"conic-gradient(#eeeeee 0 25%, transparent 0 50%, #eeeeee 0 75%, transparent 0)",backgroundSize:"var(--size) var(--size)",inset:"0px",zIndex:"auto",pointerEvents:"none"}})},getChannelSliderProps(props){const{orientation="horizontal",channel}=props;return normalize.element({...parts.channelSlider.attrs,"data-channel":channel,"data-orientation":orientation,role:"presentation",onPointerDown(event){if(!interactive)return;if(!isLeftClick(event))return;if(isModifierKey(event))return;const point=getEventPoint(event);send({type:"CHANNEL_SLIDER.POINTER_DOWN",channel,point,id:channel,orientation});event.preventDefault()},style:{position:"relative",touchAction:"none"}})},getChannelSliderTrackProps(props){const{orientation="horizontal",channel}=props;return normalize.element({...parts.channelSliderTrack.attrs,id:dom.getChannelSliderId(state.context,channel),role:"group","data-channel":channel,"data-orientation":orientation,style:{position:"relative",forcedColorAdjust:"none",backgroundImage:getSliderBackground({orientation,channel,dir:state.context.dir,value:areaValue})}})},getChannelSliderThumbProps(props){const{orientation="horizontal",channel}=props;const{minValue,maxValue,step:stepValue}=areaValue.getChannelRange(channel);const channelValue=areaValue.getChannelValue(channel);const offset=(channelValue-minValue)/(maxValue-minValue);const placementStyles=orientation==="horizontal"?{left:`${offset*100}%`,top:"50%"}:{top:`${offset*100}%`,left:"50%"};return normalize.element({...parts.channelSliderThumb.attrs,id:dom.getChannelSliderThumbId(state.context,channel),role:"slider","aria-label":channel,tabIndex:disabled?void 0:0,"data-channel":channel,"data-disabled":dataAttr(disabled),"data-orientation":orientation,"aria-disabled":dataAttr(disabled),"aria-orientation":orientation,"aria-valuemax":maxValue,"aria-valuemin":minValue,"aria-valuenow":channelValue,"aria-valuetext":`${channel} ${channelValue}`,style:{forcedColorAdjust:"none",position:"absolute",background:getChannelDisplayColor(areaValue,channel).toString("css"),...placementStyles},onFocus(){if(!interactive)return;send({type:"CHANNEL_SLIDER.FOCUS",channel})},onKeyDown(event){if(event.defaultPrevented)return;if(!interactive)return;const step=getEventStep(event)*stepValue;const keyMap={ArrowUp(){send({type:"CHANNEL_SLIDER.ARROW_UP",channel,step})},ArrowDown(){send({type:"CHANNEL_SLIDER.ARROW_DOWN",channel,step})},ArrowLeft(){send({type:"CHANNEL_SLIDER.ARROW_LEFT",channel,step})},ArrowRight(){send({type:"CHANNEL_SLIDER.ARROW_RIGHT",channel,step})},PageUp(){send({type:"CHANNEL_SLIDER.PAGE_UP",channel})},PageDown(){send({type:"CHANNEL_SLIDER.PAGE_DOWN",channel})},Home(){send({type:"CHANNEL_SLIDER.HOME",channel})},End(){send({type:"CHANNEL_SLIDER.END",channel})},Escape(event2){event2.stopPropagation()}};const exec=keyMap[getEventKey(event,state.context)];if(exec){exec(event);event.preventDefault()}}})},getChannelInputProps(props){const{channel}=props;const isTextField=channel==="hex"||channel==="css";const range=getChannelRange(value,channel);return normalize.input({...parts.channelInput.attrs,dir:state.context.dir,type:isTextField?"text":"number","data-channel":channel,"aria-label":channel,spellCheck:false,autoComplete:"off",disabled,"data-disabled":dataAttr(disabled),readOnly:state.context.readOnly,defaultValue:getChannelValue(value,channel),min:range?.minValue,max:range?.maxValue,step:range?.step,onBeforeInput(event){if(isTextField||!interactive)return;const value2=event.currentTarget.value;if(value2.match(/[^0-9.]/g)){event.preventDefault()}},onFocus(event){if(!interactive)return;send({type:"CHANNEL_INPUT.FOCUS",channel});event.target.select()},onBlur(event){if(!interactive)return;const value2=isTextField?event.currentTarget.value:event.currentTarget.valueAsNumber;send({type:"CHANNEL_INPUT.BLUR",channel,value:value2,isTextField})},onKeyDown(event){if(event.defaultPrevented)return;if(!interactive)return;if(event.key==="Enter"){const value2=isTextField?event.currentTarget.value:event.currentTarget.valueAsNumber;send({type:"CHANNEL_INPUT.CHANGE",channel,value:value2,isTextField});event.preventDefault()}},style:{appearance:"none",WebkitAppearance:"none",MozAppearance:"textfield"}})},hiddenInputProps:normalize.input({type:"text",disabled,name:state.context.name,id:dom.getHiddenInputId(state.context),style:visuallyHiddenStyle,defaultValue:valueAsString}),eyeDropperTriggerProps:normalize.button({...parts.eyeDropperTrigger.attrs,type:"button",dir:state.context.dir,disabled,"data-disabled":dataAttr(disabled),"aria-label":"Pick a color from the screen",onClick(){if(!interactive)return;send("EYEDROPPER.CLICK")}}),swatchGroupProps:normalize.element({...parts.swatchGroup.attrs,role:"group"}),getSwatchTriggerState,getSwatchTriggerProps(props){const triggerState=getSwatchTriggerState(props);return normalize.button({...parts.swatchTrigger.attrs,disabled:triggerState.disabled,dir:state.context.dir,type:"button","aria-label":`select ${triggerState.valueAsString} as the color`,"data-state":triggerState.checked?"checked":"unchecked","data-value":triggerState.valueAsString,"data-disabled":dataAttr(triggerState.disabled),onClick(){if(triggerState.disabled)return;send({type:"SWATCH_TRIGGER.CLICK",value:triggerState.value})},style:{position:"relative"}})},getSwatchIndicatorProps(props){const triggerState=getSwatchTriggerState(props);return normalize.element({...parts.swatchIndicator.attrs,dir:state.context.dir,hidden:!triggerState.checked})},getSwatchProps(props){const{respectAlpha=true}=props;const triggerState=getSwatchTriggerState(props);return normalize.element({...parts.swatch.attrs,dir:state.context.dir,"data-state":triggerState.checked?"checked":"unchecked","data-value":triggerState.valueAsString,style:{position:"relative",background:triggerState.value.toString(respectAlpha?"css":"hex")}})},formatTriggerProps:normalize.button({...parts.formatTrigger.attrs,dir:state.context.dir,type:"button","aria-label":`change color format to ${getNextFormat(state.context.format)}`,onClick(event){if(event.currentTarget.disabled)return;const nextFormat=getNextFormat(state.context.format);send({type:"FORMAT.SET",format:nextFormat,src:"format-trigger"})}}),formatSelectProps:normalize.select({...parts.formatSelect.attrs,"aria-label":"change color format",dir:state.context.dir,defaultValue:state.context.format,disabled,onChange(event){const format=assertFormat(event.currentTarget.value);send({type:"FORMAT.SET",format,src:"format-select"})}})}}var formats=["hsba","hsla","rgba"];var formatRegex=new RegExp(`^(${formats.join("|")})$`);function getNextFormat(format){const index=formats.indexOf(format);return formats[index+1]??formats[0]}function assertFormat(format){if(formatRegex.test(format))return format;throw new Error(`Unsupported color format: ${format}`)}import{parseColor as parseColor4}from"@zag-js/color-utils";import{createMachine,guards}from"@zag-js/core";import{trackDismissableElement}from"@zag-js/dismissable";import{trackPointerMove}from"@zag-js/dom-event";import{getInitialFocus,raf}from"@zag-js/dom-query";import{dispatchInputValueEvent,trackFormControl}from"@zag-js/form-utils";import{getPlacement}from"@zag-js/popper";import{disableTextSelection}from"@zag-js/text-selection";import{compact,tryCatch}from"@zag-js/utils";import{parseColor as parseColor3}from"@zag-js/color-utils";var parse=colorString=>{return parseColor3(colorString)};var{and}=guards;function machine(userContext){const ctx=compact(userContext);return createMachine({id:"color-picker",initial:ctx.open?"open":"idle",context:{dir:"ltr",value:parse("#000000"),format:"rgba",disabled:false,closeOnSelect:false,...ctx,activeId:null,activeChannel:null,activeOrientation:null,fieldsetDisabled:false,restoreFocus:true,positioning:{...ctx.positioning,placement:"bottom"}},computed:{isRtl:ctx2=>ctx2.dir==="rtl",isDisabled:ctx2=>!!ctx2.disabled||ctx2.fieldsetDisabled,isInteractive:ctx2=>!(ctx2.isDisabled||ctx2.readOnly),valueAsString:ctx2=>ctx2.value.toString(ctx2.format),areaValue:ctx2=>{const format=ctx2.format.startsWith("hsl")?"hsla":"hsba";return ctx2.value.toFormat(format)}},activities:["trackFormControl"],watch:{value:["syncInputElements"],format:["syncFormatSelectElement"],open:["toggleVisibility"]},on:{"VALUE.SET":{actions:["setValue"]},"FORMAT.SET":{actions:["setFormat"]},"CHANNEL_INPUT.CHANGE":{actions:["setChannelColorFromInput"]},"EYEDROPPER.CLICK":{actions:["openEyeDropper"]}},states:{idle:{tags:["closed"],on:{"CONTROLLED.OPEN":{target:"open",actions:["setInitialFocus"]},OPEN:[{guard:"isOpenControlled",actions:["invokeOnOpen"]},{target:"open",actions:["invokeOnOpen","setInitialFocus"]}],"TRIGGER.CLICK":[{guard:"isOpenControlled",actions:["invokeOnOpen"]},{target:"open",actions:["invokeOnOpen","setInitialFocus"]}],"CHANNEL_INPUT.FOCUS":{target:"focused",actions:["setActiveChannel"]}}},focused:{tags:["closed","focused"],on:{"CONTROLLED.OPEN":{target:"open",actions:["setInitialFocus"]},OPEN:[{guard:"isOpenControlled",actions:["invokeOnOpen"]},{target:"open",actions:["invokeOnOpen","setInitialFocus"]}],"TRIGGER.CLICK":[{guard:"isOpenControlled",actions:["invokeOnOpen"]},{target:"open",actions:["invokeOnOpen","setInitialFocus"]}],"CHANNEL_INPUT.FOCUS":{actions:["setActiveChannel"]},"CHANNEL_INPUT.BLUR":{target:"idle",actions:["setChannelColorFromInput"]},"TRIGGER.BLUR":{target:"idle"}}},open:{tags:["open"],activities:["trackPositioning","trackDismissableElement"],on:{"CONTROLLED.CLOSE":[{guard:"shouldRestoreFocus",target:"focused",actions:["setReturnFocus"]},{target:"idle"}],"TRIGGER.CLICK":[{guard:"isOpenControlled",actions:["invokeOnClose"]},{target:"idle",actions:["invokeOnClose"]}],"AREA.POINTER_DOWN":{target:"open:dragging",actions:["setActiveChannel","setAreaColorFromPoint","focusAreaThumb"]},"AREA.FOCUS":{actions:["setActiveChannel"]},"CHANNEL_SLIDER.POINTER_DOWN":{target:"open:dragging",actions:["setActiveChannel","setChannelColorFromPoint","focusChannelThumb"]},"CHANNEL_SLIDER.FOCUS":{actions:["setActiveChannel"]},"AREA.ARROW_LEFT":{actions:["decrementXChannel"]},"AREA.ARROW_RIGHT":{actions:["incrementXChannel"]},"AREA.ARROW_UP":{actions:["incrementYChannel"]},"AREA.ARROW_DOWN":{actions:["decrementYChannel"]},"AREA.PAGE_UP":{actions:["incrementXChannel"]},"AREA.PAGE_DOWN":{actions:["decrementXChannel"]},"CHANNEL_SLIDER.ARROW_LEFT":{actions:["decrementChannel"]},"CHANNEL_SLIDER.ARROW_RIGHT":{actions:["incrementChannel"]},"CHANNEL_SLIDER.ARROW_UP":{actions:["incrementChannel"]},"CHANNEL_SLIDER.ARROW_DOWN":{actions:["decrementChannel"]},"CHANNEL_SLIDER.PAGE_UP":{actions:["incrementChannel"]},"CHANNEL_SLIDER.PAGE_DOWN":{actions:["decrementChannel"]},"CHANNEL_SLIDER.HOME":{actions:["setChannelToMin"]},"CHANNEL_SLIDER.END":{actions:["setChannelToMax"]},"CHANNEL_INPUT.BLUR":{actions:["setChannelColorFromInput"]},INTERACT_OUTSIDE:[{guard:"isOpenControlled",actions:["invokeOnClose"]},{guard:"shouldRestoreFocus",target:"focused",actions:["invokeOnClose","setReturnFocus"]},{target:"idle",actions:["invokeOnClose"]}],CLOSE:[{guard:"isOpenControlled",actions:["invokeOnClose"]},{target:"idle",actions:["invokeOnClose"]}],"SWATCH_TRIGGER.CLICK":[{guard:and("isOpenControlled","closeOnSelect"),actions:["setValue","invokeOnClose"]},{guard:"closeOnSelect",target:"focused",actions:["setValue","invokeOnClose","setReturnFocus"]},{actions:["setValue"]}]}},"open:dragging":{tags:["open"],exit:["clearActiveChannel"],activities:["trackPointerMove","disableTextSelection","trackPositioning","trackDismissableElement"],on:{"CONTROLLED.CLOSE":[{guard:"shouldRestoreFocus",target:"focused",actions:["setReturnFocus"]},{target:"idle"}],"AREA.POINTER_MOVE":{actions:["setAreaColorFromPoint","focusAreaThumb"]},"AREA.POINTER_UP":{target:"open",actions:["invokeOnChangeEnd"]},"CHANNEL_SLIDER.POINTER_MOVE":{actions:["setChannelColorFromPoint","focusChannelThumb"]},"CHANNEL_SLIDER.POINTER_UP":{target:"open",actions:["invokeOnChangeEnd"]},INTERACT_OUTSIDE:[{guard:"isOpenControlled",actions:["invokeOnClose"]},{guard:"shouldRestoreFocus",target:"focused",actions:["invokeOnClose","setReturnFocus"]},{target:"idle",actions:["invokeOnClose"]}],CLOSE:[{guard:"isOpenControlled",actions:["invokeOnClose"]},{target:"idle",actions:["invokeOnClose"]}]}}}},{guards:{closeOnSelect:ctx2=>!!ctx2.closeOnSelect,isOpenControlled:ctx2=>!!ctx2["open.controlled"],shouldRestoreFocus:ctx2=>!!ctx2.restoreFocus},activities:{trackPositioning(ctx2){ctx2.currentPlacement=ctx2.positioning.placement;const anchorEl=dom.getTriggerEl(ctx2);const getPositionerEl=()=>dom.getPositionerEl(ctx2);return getPlacement(anchorEl,getPositionerEl,{...ctx2.positioning,defer:true,onComplete(data){ctx2.currentPlacement=data.placement}})},trackDismissableElement(ctx2,_evt,{send}){const getContentEl=()=>dom.getContentEl(ctx2);return trackDismissableElement(getContentEl,{exclude:dom.getTriggerEl(ctx2),defer:true,onInteractOutside(event){ctx2.onInteractOutside?.(event);if(event.defaultPrevented)return;ctx2.restoreFocus=!(event.detail.focusable||event.detail.contextmenu)},onPointerDownOutside:ctx2.onPointerDownOutside,onFocusOutside:ctx2.onFocusOutside,onDismiss(){send({type:"INTERACT_OUTSIDE"})}})},trackFormControl(ctx2,_evt,{send,initialContext}){const inputEl=dom.getHiddenInputEl(ctx2);return trackFormControl(inputEl,{onFieldsetDisabledChange(disabled){ctx2.fieldsetDisabled=disabled},onFormReset(){send({type:"VALUE.SET",value:initialContext.value,src:"form.reset"})}})},trackPointerMove(ctx2,_evt,{send}){return trackPointerMove(dom.getDoc(ctx2),{onPointerMove({point}){const type=ctx2.activeId==="area"?"AREA.POINTER_MOVE":"CHANNEL_SLIDER.POINTER_MOVE";send({type,point})},onPointerUp(){const type=ctx2.activeId==="area"?"AREA.POINTER_UP":"CHANNEL_SLIDER.POINTER_UP";send({type})}})},disableTextSelection(ctx2){return disableTextSelection({doc:dom.getDoc(ctx2),target:dom.getContentEl(ctx2)})}},actions:{openEyeDropper(ctx2){const isSupported="EyeDropper"in dom.getWin(ctx2);if(!isSupported)return;const win=dom.getWin(ctx2);const picker=new win.EyeDropper;picker.open().then(({sRGBHex})=>{const format=ctx2.value.getFormat();const color=parseColor4(sRGBHex).toFormat(format);set.value(ctx2,color);ctx2.onValueChangeEnd?.({value:ctx2.value,valueAsString:ctx2.valueAsString})}).catch(()=>void 0)},setActiveChannel(ctx2,evt){ctx2.activeId=evt.id;if(evt.channel)ctx2.activeChannel=evt.channel;if(evt.orientation)ctx2.activeOrientation=evt.orientation},clearActiveChannel(ctx2){ctx2.activeChannel=null;ctx2.activeId=null;ctx2.activeOrientation=null},setAreaColorFromPoint(ctx2,evt){const{xChannel,yChannel}=evt.channel||ctx2.activeChannel;const percent=dom.getAreaValueFromPoint(ctx2,evt.point);if(!percent)return;const xValue=ctx2.areaValue.getChannelPercentValue(xChannel,percent.x);const yValue=ctx2.areaValue.getChannelPercentValue(yChannel,1-percent.y);const color=ctx2.areaValue.withChannelValue(xChannel,xValue).withChannelValue(yChannel,yValue);set.value(ctx2,color)},setChannelColorFromPoint(ctx2,evt){const channel=evt.channel||ctx2.activeId;const percent=dom.getChannelSliderValueFromPoint(ctx2,evt.point,channel);if(!percent)return;const orientation=ctx2.activeOrientation||"horizontal";const channelPercent=orientation==="horizontal"?percent.x:percent.y;const value=ctx2.areaValue.getChannelPercentValue(channel,channelPercent);const color=ctx2.areaValue.withChannelValue(channel,value);set.value(ctx2,color)},setValue(ctx2,evt){set.value(ctx2,evt.value)},setFormat(ctx2,evt){set.format(ctx2,evt.format)},syncInputElements(ctx2){sync.inputs(ctx2)},invokeOnChangeEnd(ctx2){invoke.changeEnd(ctx2)},setChannelColorFromInput(ctx2,evt){const{channel,isTextField,value}=evt;const currentAlpha=ctx2.value.getChannelValue("alpha");let color;if(channel==="alpha"){let valueAsNumber=parseFloat(value);valueAsNumber=Number.isNaN(valueAsNumber)?currentAlpha:valueAsNumber;color=ctx2.value.withChannelValue("alpha",valueAsNumber)}else if(isTextField){color=tryCatch(()=>parse(value).withChannelValue("alpha",currentAlpha),()=>ctx2.value)}else{const current=ctx2.value.toFormat(ctx2.format);const valueAsNumber=Number.isNaN(value)?current.getChannelValue(channel):value;color=current.withChannelValue(channel,valueAsNumber)}sync.inputs(ctx2,color);set.value(ctx2,color)},incrementChannel(ctx2,evt){const color=ctx2.value.incrementChannel(evt.channel,evt.step);set.value(ctx2,color)},decrementChannel(ctx2,evt){const color=ctx2.value.decrementChannel(evt.channel,evt.step);set.value(ctx2,color)},incrementXChannel(ctx2,evt){const{xChannel}=evt.channel;const color=ctx2.areaValue.incrementChannel(xChannel,evt.step);set.value(ctx2,color)},decrementXChannel(ctx2,evt){const{xChannel}=evt.channel;const color=ctx2.areaValue.decrementChannel(xChannel,evt.step);set.value(ctx2,color)},incrementYChannel(ctx2,evt){const{yChannel}=evt.channel;const color=ctx2.areaValue.incrementChannel(yChannel,evt.step);set.value(ctx2,color)},decrementYChannel(ctx2,evt){const{yChannel}=evt.channel;const color=ctx2.areaValue.decrementChannel(yChannel,evt.step);set.value(ctx2,color)},setChannelToMax(ctx2,evt){const range=ctx2.value.getChannelRange(evt.channel);const color=ctx2.value.withChannelValue(evt.channel,range.maxValue);set.value(ctx2,color)},setChannelToMin(ctx2,evt){const range=ctx2.value.getChannelRange(evt.channel);const color=ctx2.value.withChannelValue(evt.channel,range.minValue);set.value(ctx2,color)},focusAreaThumb(ctx2){raf(()=>{dom.getAreaThumbEl(ctx2)?.focus({preventScroll:true})})},focusChannelThumb(ctx2,evt){raf(()=>{dom.getChannelSliderThumbEl(ctx2,evt.channel)?.focus({preventScroll:true})})},setInitialFocus(ctx2){raf(()=>{const element=getInitialFocus({root:dom.getContentEl(ctx2),getInitialEl:ctx2.initialFocusEl});element?.focus({preventScroll:true})})},setReturnFocus(ctx2){raf(()=>{dom.getTriggerEl(ctx2)?.focus({preventScroll:true})})},syncFormatSelectElement(ctx2){sync.formatSelect(ctx2)},invokeOnOpen(ctx2){ctx2.onOpenChange?.({open:true})},invokeOnClose(ctx2){ctx2.onOpenChange?.({open:false})},toggleVisibility(ctx2,evt,{send}){send({type:ctx2.open?"CONTROLLED.OPEN":"CONTROLLED.CLOSE",previousEvent:evt})}},compareFns:{value:(a,b)=>a.isEqual(b)}})}var sync={inputs(ctx,color){const channelInputs=dom.getChannelInputEls(ctx);raf(()=>{channelInputs.forEach(inputEl=>{const channel=inputEl.dataset.channel;dom.setValue(inputEl,getChannelValue(color||ctx.value,channel))})})},formatSelect(ctx){const selectEl=dom.getFormatSelectEl(ctx);raf(()=>{dom.setValue(selectEl,ctx.format)})}};var invoke={changeEnd(ctx){const value=ctx.value.toFormat(ctx.format);ctx.onValueChangeEnd?.({value,valueAsString:ctx.valueAsString})},change(ctx){const value=ctx.value.toFormat(ctx.format);ctx.onValueChange?.({value,valueAsString:ctx.valueAsString});dispatchInputValueEvent(dom.getHiddenInputEl(ctx),{value:ctx.valueAsString})},formatChange(ctx){ctx.onFormatChange?.({format:ctx.format})}};var set={value(ctx,color){if(!color||ctx.value.isEqual(color))return;ctx.value=color;invoke.change(ctx)},format(ctx,format){if(ctx.format===format)return;ctx.format=format;invoke.formatChange(ctx)}};export{anatomy,connect,machine,parse};
1
+ // src/color-picker.anatomy.ts
2
+ import { createAnatomy } from "@zag-js/anatomy";
3
+ var anatomy = createAnatomy("color-picker", [
4
+ "root",
5
+ "label",
6
+ "control",
7
+ "trigger",
8
+ "positioner",
9
+ "content",
10
+ "area",
11
+ "areaThumb",
12
+ "areaBackground",
13
+ "channelSlider",
14
+ "channelSliderTrack",
15
+ "channelSliderThumb",
16
+ "channelInput",
17
+ "transparencyGrid",
18
+ "swatchGroup",
19
+ "swatchTrigger",
20
+ "swatchIndicator",
21
+ "swatch",
22
+ "eyeDropperTrigger",
23
+ "formatTrigger",
24
+ "formatSelect"
25
+ ]);
26
+ var parts = anatomy.build();
27
+
28
+ // src/color-picker.connect.ts
29
+ import { getColorAreaGradient, normalizeColor } from "@zag-js/color-utils";
30
+ import {
31
+ getEventKey,
32
+ getEventPoint,
33
+ getEventStep,
34
+ isLeftClick,
35
+ isModifierKey
36
+ } from "@zag-js/dom-event";
37
+ import { dataAttr, query, visuallyHiddenStyle } from "@zag-js/dom-query";
38
+ import { getPlacementStyles } from "@zag-js/popper";
39
+
40
+ // src/color-picker.dom.ts
41
+ import { getRelativePoint } from "@zag-js/dom-event";
42
+ import { createScope, queryAll } from "@zag-js/dom-query";
43
+ var dom = createScope({
44
+ getRootId: (ctx) => ctx.ids?.root ?? `color-picker:${ctx.id}`,
45
+ getLabelId: (ctx) => ctx.ids?.label ?? `color-picker:${ctx.id}:label`,
46
+ getHiddenInputId: (ctx) => `color-picker:${ctx.id}:hidden-input`,
47
+ getControlId: (ctx) => ctx.ids?.control ?? `color-picker:${ctx.id}:control`,
48
+ getTriggerId: (ctx) => ctx.ids?.trigger ?? `color-picker:${ctx.id}:trigger`,
49
+ getContentId: (ctx) => ctx.ids?.content ?? `color-picker:${ctx.id}:content`,
50
+ getPositionerId: (ctx) => `color-picker:${ctx.id}:positioner`,
51
+ getFormatSelectId: (ctx) => `color-picker:${ctx.id}:format-select`,
52
+ getAreaId: (ctx) => ctx.ids?.area ?? `color-picker:${ctx.id}:area`,
53
+ getAreaGradientId: (ctx) => ctx.ids?.areaGradient ?? `color-picker:${ctx.id}:area-gradient`,
54
+ getAreaThumbId: (ctx) => ctx.ids?.areaThumb ?? `color-picker:${ctx.id}:area-thumb`,
55
+ getChannelSliderId: (ctx, channel) => ctx.ids?.channelSliderTrack?.(channel) ?? `color-picker:${ctx.id}:slider-track:${channel}`,
56
+ getChannelSliderThumbId: (ctx, channel) => ctx.ids?.channelSliderThumb?.(channel) ?? `color-picker:${ctx.id}:slider-thumb:${channel}`,
57
+ getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
58
+ getAreaThumbEl: (ctx) => dom.getById(ctx, dom.getAreaThumbId(ctx)),
59
+ getChannelSliderThumbEl: (ctx, channel) => dom.getById(ctx, dom.getChannelSliderThumbId(ctx, channel)),
60
+ getChannelInputEl: (ctx, channel) => {
61
+ return [
62
+ ...queryAll(dom.getContentEl(ctx), `input[data-channel="${channel}"]`),
63
+ ...queryAll(dom.getControlEl(ctx), `input[data-channel="${channel}"]`)
64
+ ];
65
+ },
66
+ getFormatSelectEl: (ctx) => dom.getById(ctx, dom.getFormatSelectId(ctx)),
67
+ getHiddenInputEl: (ctx) => dom.getById(ctx, dom.getHiddenInputId(ctx)),
68
+ getAreaEl: (ctx) => dom.getById(ctx, dom.getAreaId(ctx)),
69
+ getAreaValueFromPoint(ctx, point) {
70
+ const areaEl = dom.getAreaEl(ctx);
71
+ if (!areaEl)
72
+ return;
73
+ const { percent } = getRelativePoint(point, areaEl);
74
+ return percent;
75
+ },
76
+ getControlEl: (ctx) => dom.getById(ctx, dom.getControlId(ctx)),
77
+ getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
78
+ getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
79
+ getChannelSliderTrackEl: (ctx, channel) => {
80
+ return dom.getById(ctx, dom.getChannelSliderId(ctx, channel));
81
+ },
82
+ getChannelSliderValueFromPoint(ctx, point, channel) {
83
+ const trackEl = dom.getChannelSliderTrackEl(ctx, channel);
84
+ if (!trackEl)
85
+ return;
86
+ const { percent } = getRelativePoint(point, trackEl);
87
+ return percent;
88
+ },
89
+ getChannelInputEls: (ctx) => {
90
+ return [
91
+ ...queryAll(dom.getContentEl(ctx), "input[data-channel]"),
92
+ ...queryAll(dom.getControlEl(ctx), "input[data-channel]")
93
+ ];
94
+ }
95
+ });
96
+
97
+ // src/utils/get-channel-display-color.ts
98
+ import { parseColor } from "@zag-js/color-utils";
99
+ function getChannelDisplayColor(color, channel) {
100
+ switch (channel) {
101
+ case "hue":
102
+ return parseColor(`hsl(${color.getChannelValue("hue")}, 100%, 50%)`);
103
+ case "lightness":
104
+ case "brightness":
105
+ case "saturation":
106
+ case "red":
107
+ case "green":
108
+ case "blue":
109
+ return color.withChannelValue("alpha", 1);
110
+ case "alpha": {
111
+ return color;
112
+ }
113
+ default:
114
+ throw new Error("Unknown color channel: " + channel);
115
+ }
116
+ }
117
+
118
+ // src/utils/get-channel-input-value.ts
119
+ import { parseColor as parseColor2 } from "@zag-js/color-utils";
120
+ function getChannelValue(color, channel) {
121
+ if (channel == null)
122
+ return "";
123
+ if (channel === "hex") {
124
+ return color.toString("hex");
125
+ }
126
+ if (channel === "css") {
127
+ return color.toString("css");
128
+ }
129
+ if (channel in color) {
130
+ return color.getChannelValue(channel).toString();
131
+ }
132
+ const isHSL = color.getFormat() === "hsla";
133
+ switch (channel) {
134
+ case "hue":
135
+ return isHSL ? color.toFormat("hsla").getChannelValue("hue").toString() : color.toFormat("hsba").getChannelValue("hue").toString();
136
+ case "saturation":
137
+ return isHSL ? color.toFormat("hsla").getChannelValue("saturation").toString() : color.toFormat("hsba").getChannelValue("saturation").toString();
138
+ case "lightness":
139
+ return color.toFormat("hsla").getChannelValue("lightness").toString();
140
+ case "brightness":
141
+ return color.toFormat("hsba").getChannelValue("brightness").toString();
142
+ case "red":
143
+ case "green":
144
+ case "blue":
145
+ return color.toFormat("rgba").getChannelValue(channel).toString();
146
+ default:
147
+ return color.getChannelValue(channel).toString();
148
+ }
149
+ }
150
+ function getChannelRange(color, channel) {
151
+ switch (channel) {
152
+ case "hex":
153
+ const minColor = parseColor2("#000000");
154
+ const maxColor = parseColor2("#FFFFFF");
155
+ return {
156
+ minValue: minColor.toHexInt(),
157
+ maxValue: maxColor.toHexInt(),
158
+ pageSize: 10,
159
+ step: 1
160
+ };
161
+ case "css":
162
+ return void 0;
163
+ case "hue":
164
+ case "saturation":
165
+ case "lightness":
166
+ return color.toFormat("hsla").getChannelRange(channel);
167
+ case "brightness":
168
+ return color.toFormat("hsba").getChannelRange(channel);
169
+ case "red":
170
+ case "green":
171
+ case "blue":
172
+ return color.toFormat("rgba").getChannelRange(channel);
173
+ default:
174
+ return color.getChannelRange(channel);
175
+ }
176
+ }
177
+
178
+ // src/utils/get-slider-background.ts
179
+ function getSliderBackgroundDirection(orientation, dir) {
180
+ if (orientation === "vertical") {
181
+ return "top";
182
+ } else if (dir === "ltr") {
183
+ return "right";
184
+ } else {
185
+ return "left";
186
+ }
187
+ }
188
+ var getSliderBackground = (props) => {
189
+ const { channel, value, dir } = props;
190
+ const bgDirection = getSliderBackgroundDirection(props.orientation, dir);
191
+ const { minValue, maxValue } = value.getChannelRange(channel);
192
+ switch (channel) {
193
+ case "hue":
194
+ return `linear-gradient(to ${bgDirection}, rgb(255, 0, 0) 0%, rgb(255, 255, 0) 17%, rgb(0, 255, 0) 33%, rgb(0, 255, 255) 50%, rgb(0, 0, 255) 67%, rgb(255, 0, 255) 83%, rgb(255, 0, 0) 100%)`;
195
+ case "lightness": {
196
+ let start = value.withChannelValue(channel, minValue).toString("css");
197
+ let middle = value.withChannelValue(channel, (maxValue - minValue) / 2).toString("css");
198
+ let end = value.withChannelValue(channel, maxValue).toString("css");
199
+ return `linear-gradient(to ${bgDirection}, ${start}, ${middle}, ${end})`;
200
+ }
201
+ case "saturation":
202
+ case "brightness":
203
+ case "red":
204
+ case "green":
205
+ case "blue":
206
+ case "alpha": {
207
+ let start = value.withChannelValue(channel, minValue).toString("css");
208
+ let end = value.withChannelValue(channel, maxValue).toString("css");
209
+ return `linear-gradient(to ${bgDirection}, ${start}, ${end})`;
210
+ }
211
+ default:
212
+ throw new Error("Unknown color channel: " + channel);
213
+ }
214
+ };
215
+
216
+ // src/color-picker.connect.ts
217
+ function connect(state, send, normalize) {
218
+ const value = state.context.value;
219
+ const areaValue = state.context.areaValue;
220
+ const valueAsString = state.context.valueAsString;
221
+ const disabled = state.context.isDisabled;
222
+ const interactive = state.context.isInteractive;
223
+ const dragging = state.hasTag("dragging");
224
+ const open = state.hasTag("open");
225
+ const focused = state.hasTag("focused");
226
+ const getAreaChannels = (props) => {
227
+ const channels = areaValue.getChannels();
228
+ return {
229
+ xChannel: props.xChannel ?? channels[1],
230
+ yChannel: props.yChannel ?? channels[2]
231
+ };
232
+ };
233
+ const currentPlacement = state.context.currentPlacement;
234
+ const popperStyles = getPlacementStyles({
235
+ ...state.context.positioning,
236
+ placement: currentPlacement
237
+ });
238
+ function getSwatchTriggerState(props) {
239
+ const color = normalizeColor(props.value).toFormat(state.context.format);
240
+ return {
241
+ value: color,
242
+ valueAsString: color.toString("hex"),
243
+ checked: color.isEqual(value),
244
+ disabled: props.disabled || !interactive
245
+ };
246
+ }
247
+ return {
248
+ dragging,
249
+ open,
250
+ valueAsString,
251
+ value,
252
+ setOpen(nextOpen) {
253
+ if (nextOpen === open)
254
+ return;
255
+ send({ type: nextOpen ? "OPEN" : "CLOSE" });
256
+ },
257
+ setValue(value2) {
258
+ send({ type: "VALUE.SET", value: normalizeColor(value2), src: "set-color" });
259
+ },
260
+ getChannelValue(channel) {
261
+ return getChannelValue(value, channel);
262
+ },
263
+ setChannelValue(channel, channelValue) {
264
+ const color = value.withChannelValue(channel, channelValue);
265
+ send({ type: "VALUE.SET", value: color, src: "set-channel" });
266
+ },
267
+ format: state.context.format,
268
+ setFormat(format) {
269
+ const formatValue = value.toFormat(format);
270
+ send({ type: "VALUE.SET", value: formatValue, src: "set-format" });
271
+ },
272
+ alpha: value.getChannelValue("alpha"),
273
+ setAlpha(alphaValue) {
274
+ const color = value.withChannelValue("alpha", alphaValue);
275
+ send({ type: "VALUE.SET", value: color, src: "set-alpha" });
276
+ },
277
+ getRootProps() {
278
+ return normalize.element({
279
+ ...parts.root.attrs,
280
+ dir: state.context.dir,
281
+ id: dom.getRootId(state.context),
282
+ "data-disabled": dataAttr(disabled),
283
+ "data-readonly": dataAttr(state.context.readOnly),
284
+ style: {
285
+ "--value": value.toString("css")
286
+ }
287
+ });
288
+ },
289
+ getLabelProps() {
290
+ return normalize.element({
291
+ ...parts.label.attrs,
292
+ dir: state.context.dir,
293
+ id: dom.getLabelId(state.context),
294
+ htmlFor: dom.getHiddenInputId(state.context),
295
+ "data-disabled": dataAttr(disabled),
296
+ "data-readonly": dataAttr(state.context.readOnly),
297
+ "data-focus": dataAttr(focused),
298
+ onClick(event) {
299
+ event.preventDefault();
300
+ const inputEl = query(dom.getControlEl(state.context), "[data-channel=hex]");
301
+ inputEl?.focus({ preventScroll: true });
302
+ }
303
+ });
304
+ },
305
+ getControlProps() {
306
+ return normalize.element({
307
+ ...parts.control.attrs,
308
+ id: dom.getControlId(state.context),
309
+ dir: state.context.dir,
310
+ "data-disabled": dataAttr(disabled),
311
+ "data-readonly": dataAttr(state.context.readOnly),
312
+ "data-state": open ? "open" : "closed",
313
+ "data-focus": dataAttr(focused)
314
+ });
315
+ },
316
+ getTriggerProps() {
317
+ return normalize.button({
318
+ ...parts.trigger.attrs,
319
+ id: dom.getTriggerId(state.context),
320
+ dir: state.context.dir,
321
+ disabled,
322
+ "aria-label": `select color. current color is ${valueAsString}`,
323
+ "aria-controls": dom.getContentId(state.context),
324
+ "aria-labelledby": dom.getLabelId(state.context),
325
+ "data-disabled": dataAttr(disabled),
326
+ "data-readonly": dataAttr(state.context.readOnly),
327
+ "data-placement": currentPlacement,
328
+ "aria-expanded": dataAttr(open),
329
+ "data-state": open ? "open" : "closed",
330
+ "data-focus": dataAttr(focused),
331
+ type: "button",
332
+ onClick() {
333
+ if (!interactive)
334
+ return;
335
+ send({ type: "TRIGGER.CLICK" });
336
+ },
337
+ onBlur() {
338
+ if (!interactive)
339
+ return;
340
+ send({ type: "TRIGGER.BLUR" });
341
+ },
342
+ style: {
343
+ position: "relative"
344
+ }
345
+ });
346
+ },
347
+ getPositionerProps() {
348
+ return normalize.element({
349
+ ...parts.positioner.attrs,
350
+ id: dom.getPositionerId(state.context),
351
+ dir: state.context.dir,
352
+ style: popperStyles.floating
353
+ });
354
+ },
355
+ getContentProps() {
356
+ return normalize.element({
357
+ ...parts.content.attrs,
358
+ id: dom.getContentId(state.context),
359
+ dir: state.context.dir,
360
+ "data-placement": currentPlacement,
361
+ "data-state": open ? "open" : "closed",
362
+ hidden: !open
363
+ });
364
+ },
365
+ getAreaProps(props = {}) {
366
+ const { xChannel, yChannel } = getAreaChannels(props);
367
+ const { areaStyles } = getColorAreaGradient(areaValue, {
368
+ xChannel,
369
+ yChannel,
370
+ dir: state.context.dir
371
+ });
372
+ return normalize.element({
373
+ ...parts.area.attrs,
374
+ id: dom.getAreaId(state.context),
375
+ role: "group",
376
+ onPointerDown(event) {
377
+ if (!interactive)
378
+ return;
379
+ if (!isLeftClick(event))
380
+ return;
381
+ if (isModifierKey(event))
382
+ return;
383
+ const point = getEventPoint(event);
384
+ const channel = { xChannel, yChannel };
385
+ send({ type: "AREA.POINTER_DOWN", point, channel, id: "area" });
386
+ event.preventDefault();
387
+ },
388
+ style: {
389
+ position: "relative",
390
+ touchAction: "none",
391
+ forcedColorAdjust: "none",
392
+ ...areaStyles
393
+ }
394
+ });
395
+ },
396
+ getAreaBackgroundProps(props = {}) {
397
+ const { xChannel, yChannel } = getAreaChannels(props);
398
+ const { areaGradientStyles } = getColorAreaGradient(areaValue, {
399
+ xChannel,
400
+ yChannel,
401
+ dir: state.context.dir
402
+ });
403
+ return normalize.element({
404
+ ...parts.areaBackground.attrs,
405
+ id: dom.getAreaGradientId(state.context),
406
+ style: {
407
+ position: "relative",
408
+ touchAction: "none",
409
+ forcedColorAdjust: "none",
410
+ ...areaGradientStyles
411
+ }
412
+ });
413
+ },
414
+ getAreaThumbProps(props = {}) {
415
+ const { xChannel, yChannel } = getAreaChannels(props);
416
+ const channel = { xChannel, yChannel };
417
+ const xPercent = areaValue.getChannelValuePercent(xChannel);
418
+ const yPercent = 1 - areaValue.getChannelValuePercent(yChannel);
419
+ const xValue = areaValue.getChannelValue(xChannel);
420
+ const yValue = areaValue.getChannelValue(yChannel);
421
+ return normalize.element({
422
+ ...parts.areaThumb.attrs,
423
+ id: dom.getAreaThumbId(state.context),
424
+ dir: state.context.dir,
425
+ tabIndex: disabled ? void 0 : 0,
426
+ "data-disabled": dataAttr(disabled),
427
+ role: "slider",
428
+ "aria-valuemin": 0,
429
+ "aria-valuemax": 100,
430
+ "aria-valuenow": xValue,
431
+ "aria-label": `${xChannel} and ${yChannel}`,
432
+ "aria-roledescription": "2d slider",
433
+ "aria-valuetext": `${xChannel} ${xValue}, ${yChannel} ${yValue}`,
434
+ style: {
435
+ position: "absolute",
436
+ left: `${xPercent * 100}%`,
437
+ top: `${yPercent * 100}%`,
438
+ transform: "translate(-50%, -50%)",
439
+ touchAction: "none",
440
+ forcedColorAdjust: "none",
441
+ background: areaValue.withChannelValue("alpha", 1).toString("css")
442
+ },
443
+ onFocus() {
444
+ if (!interactive)
445
+ return;
446
+ send({ type: "AREA.FOCUS", id: "area", channel });
447
+ },
448
+ onKeyDown(event) {
449
+ if (event.defaultPrevented)
450
+ return;
451
+ if (!interactive)
452
+ return;
453
+ const step = getEventStep(event);
454
+ const keyMap = {
455
+ ArrowUp() {
456
+ send({ type: "AREA.ARROW_UP", channel, step });
457
+ },
458
+ ArrowDown() {
459
+ send({ type: "AREA.ARROW_DOWN", channel, step });
460
+ },
461
+ ArrowLeft() {
462
+ send({ type: "AREA.ARROW_LEFT", channel, step });
463
+ },
464
+ ArrowRight() {
465
+ send({ type: "AREA.ARROW_RIGHT", channel, step });
466
+ },
467
+ PageUp() {
468
+ send({ type: "AREA.PAGE_UP", channel, step });
469
+ },
470
+ PageDown() {
471
+ send({ type: "AREA.PAGE_DOWN", channel, step });
472
+ },
473
+ Escape(event2) {
474
+ event2.stopPropagation();
475
+ }
476
+ };
477
+ const exec = keyMap[getEventKey(event, state.context)];
478
+ if (exec) {
479
+ exec(event);
480
+ event.preventDefault();
481
+ }
482
+ }
483
+ });
484
+ },
485
+ getTransparencyGridProps(props = {}) {
486
+ const { size = "12px" } = props;
487
+ return normalize.element({
488
+ ...parts.transparencyGrid.attrs,
489
+ style: {
490
+ "--size": size,
491
+ width: "100%",
492
+ height: "100%",
493
+ position: "absolute",
494
+ backgroundColor: "#fff",
495
+ backgroundImage: "conic-gradient(#eeeeee 0 25%, transparent 0 50%, #eeeeee 0 75%, transparent 0)",
496
+ backgroundSize: "var(--size) var(--size)",
497
+ inset: "0px",
498
+ zIndex: "auto",
499
+ pointerEvents: "none"
500
+ }
501
+ });
502
+ },
503
+ getChannelSliderProps(props) {
504
+ const { orientation = "horizontal", channel } = props;
505
+ return normalize.element({
506
+ ...parts.channelSlider.attrs,
507
+ "data-channel": channel,
508
+ "data-orientation": orientation,
509
+ role: "presentation",
510
+ onPointerDown(event) {
511
+ if (!interactive)
512
+ return;
513
+ if (!isLeftClick(event))
514
+ return;
515
+ if (isModifierKey(event))
516
+ return;
517
+ const point = getEventPoint(event);
518
+ send({ type: "CHANNEL_SLIDER.POINTER_DOWN", channel, point, id: channel, orientation });
519
+ event.preventDefault();
520
+ },
521
+ style: {
522
+ position: "relative",
523
+ touchAction: "none"
524
+ }
525
+ });
526
+ },
527
+ getChannelSliderTrackProps(props) {
528
+ const { orientation = "horizontal", channel } = props;
529
+ return normalize.element({
530
+ ...parts.channelSliderTrack.attrs,
531
+ id: dom.getChannelSliderId(state.context, channel),
532
+ role: "group",
533
+ "data-channel": channel,
534
+ "data-orientation": orientation,
535
+ style: {
536
+ position: "relative",
537
+ forcedColorAdjust: "none",
538
+ backgroundImage: getSliderBackground({
539
+ orientation,
540
+ channel,
541
+ dir: state.context.dir,
542
+ value: areaValue
543
+ })
544
+ }
545
+ });
546
+ },
547
+ getChannelSliderThumbProps(props) {
548
+ const { orientation = "horizontal", channel } = props;
549
+ const { minValue, maxValue, step: stepValue } = areaValue.getChannelRange(channel);
550
+ const channelValue = areaValue.getChannelValue(channel);
551
+ const offset = (channelValue - minValue) / (maxValue - minValue);
552
+ const placementStyles = orientation === "horizontal" ? { left: `${offset * 100}%`, top: "50%" } : { top: `${offset * 100}%`, left: "50%" };
553
+ return normalize.element({
554
+ ...parts.channelSliderThumb.attrs,
555
+ id: dom.getChannelSliderThumbId(state.context, channel),
556
+ role: "slider",
557
+ "aria-label": channel,
558
+ tabIndex: disabled ? void 0 : 0,
559
+ "data-channel": channel,
560
+ "data-disabled": dataAttr(disabled),
561
+ "data-orientation": orientation,
562
+ "aria-disabled": dataAttr(disabled),
563
+ "aria-orientation": orientation,
564
+ "aria-valuemax": maxValue,
565
+ "aria-valuemin": minValue,
566
+ "aria-valuenow": channelValue,
567
+ "aria-valuetext": `${channel} ${channelValue}`,
568
+ style: {
569
+ forcedColorAdjust: "none",
570
+ position: "absolute",
571
+ background: getChannelDisplayColor(areaValue, channel).toString("css"),
572
+ ...placementStyles
573
+ },
574
+ onFocus() {
575
+ if (!interactive)
576
+ return;
577
+ send({ type: "CHANNEL_SLIDER.FOCUS", channel });
578
+ },
579
+ onKeyDown(event) {
580
+ if (event.defaultPrevented)
581
+ return;
582
+ if (!interactive)
583
+ return;
584
+ const step = getEventStep(event) * stepValue;
585
+ const keyMap = {
586
+ ArrowUp() {
587
+ send({ type: "CHANNEL_SLIDER.ARROW_UP", channel, step });
588
+ },
589
+ ArrowDown() {
590
+ send({ type: "CHANNEL_SLIDER.ARROW_DOWN", channel, step });
591
+ },
592
+ ArrowLeft() {
593
+ send({ type: "CHANNEL_SLIDER.ARROW_LEFT", channel, step });
594
+ },
595
+ ArrowRight() {
596
+ send({ type: "CHANNEL_SLIDER.ARROW_RIGHT", channel, step });
597
+ },
598
+ PageUp() {
599
+ send({ type: "CHANNEL_SLIDER.PAGE_UP", channel });
600
+ },
601
+ PageDown() {
602
+ send({ type: "CHANNEL_SLIDER.PAGE_DOWN", channel });
603
+ },
604
+ Home() {
605
+ send({ type: "CHANNEL_SLIDER.HOME", channel });
606
+ },
607
+ End() {
608
+ send({ type: "CHANNEL_SLIDER.END", channel });
609
+ },
610
+ Escape(event2) {
611
+ event2.stopPropagation();
612
+ }
613
+ };
614
+ const exec = keyMap[getEventKey(event, state.context)];
615
+ if (exec) {
616
+ exec(event);
617
+ event.preventDefault();
618
+ }
619
+ }
620
+ });
621
+ },
622
+ getChannelInputProps(props) {
623
+ const { channel } = props;
624
+ const isTextField = channel === "hex" || channel === "css";
625
+ const range = getChannelRange(value, channel);
626
+ return normalize.input({
627
+ ...parts.channelInput.attrs,
628
+ dir: state.context.dir,
629
+ type: isTextField ? "text" : "number",
630
+ "data-channel": channel,
631
+ "aria-label": channel,
632
+ spellCheck: false,
633
+ autoComplete: "off",
634
+ disabled,
635
+ "data-disabled": dataAttr(disabled),
636
+ readOnly: state.context.readOnly,
637
+ defaultValue: getChannelValue(value, channel),
638
+ min: range?.minValue,
639
+ max: range?.maxValue,
640
+ step: range?.step,
641
+ onBeforeInput(event) {
642
+ if (isTextField || !interactive)
643
+ return;
644
+ const value2 = event.currentTarget.value;
645
+ if (value2.match(/[^0-9.]/g)) {
646
+ event.preventDefault();
647
+ }
648
+ },
649
+ onFocus(event) {
650
+ if (!interactive)
651
+ return;
652
+ send({ type: "CHANNEL_INPUT.FOCUS", channel });
653
+ event.target.select();
654
+ },
655
+ onBlur(event) {
656
+ if (!interactive)
657
+ return;
658
+ const value2 = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber;
659
+ send({ type: "CHANNEL_INPUT.BLUR", channel, value: value2, isTextField });
660
+ },
661
+ onKeyDown(event) {
662
+ if (event.defaultPrevented)
663
+ return;
664
+ if (!interactive)
665
+ return;
666
+ if (event.key === "Enter") {
667
+ const value2 = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber;
668
+ send({ type: "CHANNEL_INPUT.CHANGE", channel, value: value2, isTextField });
669
+ event.preventDefault();
670
+ }
671
+ },
672
+ style: {
673
+ appearance: "none",
674
+ WebkitAppearance: "none",
675
+ MozAppearance: "textfield"
676
+ }
677
+ });
678
+ },
679
+ getHiddenInputProps() {
680
+ return normalize.input({
681
+ type: "text",
682
+ disabled,
683
+ name: state.context.name,
684
+ id: dom.getHiddenInputId(state.context),
685
+ style: visuallyHiddenStyle,
686
+ defaultValue: valueAsString
687
+ });
688
+ },
689
+ getEyeDropperTriggerProps() {
690
+ return normalize.button({
691
+ ...parts.eyeDropperTrigger.attrs,
692
+ type: "button",
693
+ dir: state.context.dir,
694
+ disabled,
695
+ "data-disabled": dataAttr(disabled),
696
+ "aria-label": "Pick a color from the screen",
697
+ onClick() {
698
+ if (!interactive)
699
+ return;
700
+ send("EYEDROPPER.CLICK");
701
+ }
702
+ });
703
+ },
704
+ getSwatchGroupProps() {
705
+ return normalize.element({
706
+ ...parts.swatchGroup.attrs,
707
+ role: "group"
708
+ });
709
+ },
710
+ getSwatchTriggerState,
711
+ getSwatchTriggerProps(props) {
712
+ const swatchState = getSwatchTriggerState(props);
713
+ return normalize.button({
714
+ ...parts.swatchTrigger.attrs,
715
+ disabled: swatchState.disabled,
716
+ dir: state.context.dir,
717
+ type: "button",
718
+ "aria-label": `select ${swatchState.valueAsString} as the color`,
719
+ "data-state": swatchState.checked ? "checked" : "unchecked",
720
+ "data-value": swatchState.valueAsString,
721
+ "data-disabled": dataAttr(swatchState.disabled),
722
+ onClick() {
723
+ if (swatchState.disabled)
724
+ return;
725
+ send({ type: "SWATCH_TRIGGER.CLICK", value: swatchState.value });
726
+ },
727
+ style: {
728
+ position: "relative"
729
+ }
730
+ });
731
+ },
732
+ getSwatchIndicatorProps(props) {
733
+ const swatchState = getSwatchTriggerState(props);
734
+ return normalize.element({
735
+ ...parts.swatchIndicator.attrs,
736
+ dir: state.context.dir,
737
+ hidden: !swatchState.checked
738
+ });
739
+ },
740
+ getSwatchProps(props) {
741
+ const { respectAlpha = true } = props;
742
+ const swatchState = getSwatchTriggerState(props);
743
+ return normalize.element({
744
+ ...parts.swatch.attrs,
745
+ dir: state.context.dir,
746
+ "data-state": swatchState.checked ? "checked" : "unchecked",
747
+ "data-value": swatchState.valueAsString,
748
+ style: {
749
+ position: "relative",
750
+ background: swatchState.value.toString(respectAlpha ? "css" : "hex")
751
+ }
752
+ });
753
+ },
754
+ getFormatTriggerProps() {
755
+ return normalize.button({
756
+ ...parts.formatTrigger.attrs,
757
+ dir: state.context.dir,
758
+ type: "button",
759
+ "aria-label": `change color format to ${getNextFormat(state.context.format)}`,
760
+ onClick(event) {
761
+ if (event.currentTarget.disabled)
762
+ return;
763
+ const nextFormat = getNextFormat(state.context.format);
764
+ send({ type: "FORMAT.SET", format: nextFormat, src: "format-trigger" });
765
+ }
766
+ });
767
+ },
768
+ getFormatSelectProps() {
769
+ return normalize.select({
770
+ ...parts.formatSelect.attrs,
771
+ "aria-label": "change color format",
772
+ dir: state.context.dir,
773
+ defaultValue: state.context.format,
774
+ disabled,
775
+ onChange(event) {
776
+ const format = assertFormat(event.currentTarget.value);
777
+ send({ type: "FORMAT.SET", format, src: "format-select" });
778
+ }
779
+ });
780
+ }
781
+ };
782
+ }
783
+ var formats = ["hsba", "hsla", "rgba"];
784
+ var formatRegex = new RegExp(`^(${formats.join("|")})$`);
785
+ function getNextFormat(format) {
786
+ const index = formats.indexOf(format);
787
+ return formats[index + 1] ?? formats[0];
788
+ }
789
+ function assertFormat(format) {
790
+ if (formatRegex.test(format))
791
+ return format;
792
+ throw new Error(`Unsupported color format: ${format}`);
793
+ }
794
+
795
+ // src/color-picker.machine.ts
796
+ import { parseColor as parseColor4 } from "@zag-js/color-utils";
797
+ import { createMachine, guards } from "@zag-js/core";
798
+ import { trackDismissableElement } from "@zag-js/dismissable";
799
+ import { trackPointerMove } from "@zag-js/dom-event";
800
+ import { getInitialFocus, raf } from "@zag-js/dom-query";
801
+ import { dispatchInputValueEvent, trackFormControl } from "@zag-js/form-utils";
802
+ import { getPlacement } from "@zag-js/popper";
803
+ import { disableTextSelection } from "@zag-js/text-selection";
804
+ import { compact, tryCatch } from "@zag-js/utils";
805
+
806
+ // src/color-picker.parse.ts
807
+ import { parseColor as parseColor3 } from "@zag-js/color-utils";
808
+ var parse = (colorString) => {
809
+ return parseColor3(colorString);
810
+ };
811
+
812
+ // src/color-picker.machine.ts
813
+ var { and } = guards;
814
+ function machine(userContext) {
815
+ const ctx = compact(userContext);
816
+ return createMachine(
817
+ {
818
+ id: "color-picker",
819
+ initial: ctx.open ? "open" : "idle",
820
+ context: {
821
+ dir: "ltr",
822
+ value: parse("#000000"),
823
+ format: "rgba",
824
+ disabled: false,
825
+ closeOnSelect: false,
826
+ ...ctx,
827
+ activeId: null,
828
+ activeChannel: null,
829
+ activeOrientation: null,
830
+ fieldsetDisabled: false,
831
+ restoreFocus: true,
832
+ positioning: {
833
+ ...ctx.positioning,
834
+ placement: "bottom"
835
+ }
836
+ },
837
+ computed: {
838
+ isRtl: (ctx2) => ctx2.dir === "rtl",
839
+ isDisabled: (ctx2) => !!ctx2.disabled || ctx2.fieldsetDisabled,
840
+ isInteractive: (ctx2) => !(ctx2.isDisabled || ctx2.readOnly),
841
+ valueAsString: (ctx2) => ctx2.value.toString(ctx2.format),
842
+ areaValue: (ctx2) => {
843
+ const format = ctx2.format.startsWith("hsl") ? "hsla" : "hsba";
844
+ return ctx2.value.toFormat(format);
845
+ }
846
+ },
847
+ activities: ["trackFormControl"],
848
+ watch: {
849
+ value: ["syncInputElements"],
850
+ format: ["syncFormatSelectElement"],
851
+ open: ["toggleVisibility"]
852
+ },
853
+ on: {
854
+ "VALUE.SET": {
855
+ actions: ["setValue"]
856
+ },
857
+ "FORMAT.SET": {
858
+ actions: ["setFormat"]
859
+ },
860
+ "CHANNEL_INPUT.CHANGE": {
861
+ actions: ["setChannelColorFromInput"]
862
+ },
863
+ "EYEDROPPER.CLICK": {
864
+ actions: ["openEyeDropper"]
865
+ }
866
+ },
867
+ states: {
868
+ idle: {
869
+ tags: ["closed"],
870
+ on: {
871
+ "CONTROLLED.OPEN": {
872
+ target: "open",
873
+ actions: ["setInitialFocus"]
874
+ },
875
+ OPEN: [
876
+ {
877
+ guard: "isOpenControlled",
878
+ actions: ["invokeOnOpen"]
879
+ },
880
+ {
881
+ target: "open",
882
+ actions: ["invokeOnOpen", "setInitialFocus"]
883
+ }
884
+ ],
885
+ "TRIGGER.CLICK": [
886
+ {
887
+ guard: "isOpenControlled",
888
+ actions: ["invokeOnOpen"]
889
+ },
890
+ {
891
+ target: "open",
892
+ actions: ["invokeOnOpen", "setInitialFocus"]
893
+ }
894
+ ],
895
+ "CHANNEL_INPUT.FOCUS": {
896
+ target: "focused",
897
+ actions: ["setActiveChannel"]
898
+ }
899
+ }
900
+ },
901
+ focused: {
902
+ tags: ["closed", "focused"],
903
+ on: {
904
+ "CONTROLLED.OPEN": {
905
+ target: "open",
906
+ actions: ["setInitialFocus"]
907
+ },
908
+ OPEN: [
909
+ {
910
+ guard: "isOpenControlled",
911
+ actions: ["invokeOnOpen"]
912
+ },
913
+ {
914
+ target: "open",
915
+ actions: ["invokeOnOpen", "setInitialFocus"]
916
+ }
917
+ ],
918
+ "TRIGGER.CLICK": [
919
+ {
920
+ guard: "isOpenControlled",
921
+ actions: ["invokeOnOpen"]
922
+ },
923
+ {
924
+ target: "open",
925
+ actions: ["invokeOnOpen", "setInitialFocus"]
926
+ }
927
+ ],
928
+ "CHANNEL_INPUT.FOCUS": {
929
+ actions: ["setActiveChannel"]
930
+ },
931
+ "CHANNEL_INPUT.BLUR": {
932
+ target: "idle",
933
+ actions: ["setChannelColorFromInput"]
934
+ },
935
+ "TRIGGER.BLUR": {
936
+ target: "idle"
937
+ }
938
+ }
939
+ },
940
+ open: {
941
+ tags: ["open"],
942
+ activities: ["trackPositioning", "trackDismissableElement"],
943
+ on: {
944
+ "CONTROLLED.CLOSE": [
945
+ {
946
+ guard: "shouldRestoreFocus",
947
+ target: "focused",
948
+ actions: ["setReturnFocus"]
949
+ },
950
+ {
951
+ target: "idle"
952
+ }
953
+ ],
954
+ "TRIGGER.CLICK": [
955
+ {
956
+ guard: "isOpenControlled",
957
+ actions: ["invokeOnClose"]
958
+ },
959
+ {
960
+ target: "idle",
961
+ actions: ["invokeOnClose"]
962
+ }
963
+ ],
964
+ "AREA.POINTER_DOWN": {
965
+ target: "open:dragging",
966
+ actions: ["setActiveChannel", "setAreaColorFromPoint", "focusAreaThumb"]
967
+ },
968
+ "AREA.FOCUS": {
969
+ actions: ["setActiveChannel"]
970
+ },
971
+ "CHANNEL_SLIDER.POINTER_DOWN": {
972
+ target: "open:dragging",
973
+ actions: ["setActiveChannel", "setChannelColorFromPoint", "focusChannelThumb"]
974
+ },
975
+ "CHANNEL_SLIDER.FOCUS": {
976
+ actions: ["setActiveChannel"]
977
+ },
978
+ "AREA.ARROW_LEFT": {
979
+ actions: ["decrementXChannel"]
980
+ },
981
+ "AREA.ARROW_RIGHT": {
982
+ actions: ["incrementXChannel"]
983
+ },
984
+ "AREA.ARROW_UP": {
985
+ actions: ["incrementYChannel"]
986
+ },
987
+ "AREA.ARROW_DOWN": {
988
+ actions: ["decrementYChannel"]
989
+ },
990
+ "AREA.PAGE_UP": {
991
+ actions: ["incrementXChannel"]
992
+ },
993
+ "AREA.PAGE_DOWN": {
994
+ actions: ["decrementXChannel"]
995
+ },
996
+ "CHANNEL_SLIDER.ARROW_LEFT": {
997
+ actions: ["decrementChannel"]
998
+ },
999
+ "CHANNEL_SLIDER.ARROW_RIGHT": {
1000
+ actions: ["incrementChannel"]
1001
+ },
1002
+ "CHANNEL_SLIDER.ARROW_UP": {
1003
+ actions: ["incrementChannel"]
1004
+ },
1005
+ "CHANNEL_SLIDER.ARROW_DOWN": {
1006
+ actions: ["decrementChannel"]
1007
+ },
1008
+ "CHANNEL_SLIDER.PAGE_UP": {
1009
+ actions: ["incrementChannel"]
1010
+ },
1011
+ "CHANNEL_SLIDER.PAGE_DOWN": {
1012
+ actions: ["decrementChannel"]
1013
+ },
1014
+ "CHANNEL_SLIDER.HOME": {
1015
+ actions: ["setChannelToMin"]
1016
+ },
1017
+ "CHANNEL_SLIDER.END": {
1018
+ actions: ["setChannelToMax"]
1019
+ },
1020
+ "CHANNEL_INPUT.BLUR": {
1021
+ actions: ["setChannelColorFromInput"]
1022
+ },
1023
+ INTERACT_OUTSIDE: [
1024
+ {
1025
+ guard: "isOpenControlled",
1026
+ actions: ["invokeOnClose"]
1027
+ },
1028
+ {
1029
+ guard: "shouldRestoreFocus",
1030
+ target: "focused",
1031
+ actions: ["invokeOnClose", "setReturnFocus"]
1032
+ },
1033
+ {
1034
+ target: "idle",
1035
+ actions: ["invokeOnClose"]
1036
+ }
1037
+ ],
1038
+ CLOSE: [
1039
+ {
1040
+ guard: "isOpenControlled",
1041
+ actions: ["invokeOnClose"]
1042
+ },
1043
+ {
1044
+ target: "idle",
1045
+ actions: ["invokeOnClose"]
1046
+ }
1047
+ ],
1048
+ "SWATCH_TRIGGER.CLICK": [
1049
+ {
1050
+ guard: and("isOpenControlled", "closeOnSelect"),
1051
+ actions: ["setValue", "invokeOnClose"]
1052
+ },
1053
+ {
1054
+ guard: "closeOnSelect",
1055
+ target: "focused",
1056
+ actions: ["setValue", "invokeOnClose", "setReturnFocus"]
1057
+ },
1058
+ {
1059
+ actions: ["setValue"]
1060
+ }
1061
+ ]
1062
+ }
1063
+ },
1064
+ "open:dragging": {
1065
+ tags: ["open"],
1066
+ exit: ["clearActiveChannel"],
1067
+ activities: ["trackPointerMove", "disableTextSelection", "trackPositioning", "trackDismissableElement"],
1068
+ on: {
1069
+ "CONTROLLED.CLOSE": [
1070
+ {
1071
+ guard: "shouldRestoreFocus",
1072
+ target: "focused",
1073
+ actions: ["setReturnFocus"]
1074
+ },
1075
+ {
1076
+ target: "idle"
1077
+ }
1078
+ ],
1079
+ "AREA.POINTER_MOVE": {
1080
+ actions: ["setAreaColorFromPoint", "focusAreaThumb"]
1081
+ },
1082
+ "AREA.POINTER_UP": {
1083
+ target: "open",
1084
+ actions: ["invokeOnChangeEnd"]
1085
+ },
1086
+ "CHANNEL_SLIDER.POINTER_MOVE": {
1087
+ actions: ["setChannelColorFromPoint", "focusChannelThumb"]
1088
+ },
1089
+ "CHANNEL_SLIDER.POINTER_UP": {
1090
+ target: "open",
1091
+ actions: ["invokeOnChangeEnd"]
1092
+ },
1093
+ INTERACT_OUTSIDE: [
1094
+ {
1095
+ guard: "isOpenControlled",
1096
+ actions: ["invokeOnClose"]
1097
+ },
1098
+ {
1099
+ guard: "shouldRestoreFocus",
1100
+ target: "focused",
1101
+ actions: ["invokeOnClose", "setReturnFocus"]
1102
+ },
1103
+ {
1104
+ target: "idle",
1105
+ actions: ["invokeOnClose"]
1106
+ }
1107
+ ],
1108
+ CLOSE: [
1109
+ {
1110
+ guard: "isOpenControlled",
1111
+ actions: ["invokeOnClose"]
1112
+ },
1113
+ {
1114
+ target: "idle",
1115
+ actions: ["invokeOnClose"]
1116
+ }
1117
+ ]
1118
+ }
1119
+ }
1120
+ }
1121
+ },
1122
+ {
1123
+ guards: {
1124
+ closeOnSelect: (ctx2) => !!ctx2.closeOnSelect,
1125
+ isOpenControlled: (ctx2) => !!ctx2["open.controlled"],
1126
+ shouldRestoreFocus: (ctx2) => !!ctx2.restoreFocus
1127
+ },
1128
+ activities: {
1129
+ trackPositioning(ctx2) {
1130
+ ctx2.currentPlacement = ctx2.positioning.placement;
1131
+ const anchorEl = dom.getTriggerEl(ctx2);
1132
+ const getPositionerEl = () => dom.getPositionerEl(ctx2);
1133
+ return getPlacement(anchorEl, getPositionerEl, {
1134
+ ...ctx2.positioning,
1135
+ defer: true,
1136
+ onComplete(data) {
1137
+ ctx2.currentPlacement = data.placement;
1138
+ }
1139
+ });
1140
+ },
1141
+ trackDismissableElement(ctx2, _evt, { send }) {
1142
+ const getContentEl = () => dom.getContentEl(ctx2);
1143
+ return trackDismissableElement(getContentEl, {
1144
+ exclude: dom.getTriggerEl(ctx2),
1145
+ defer: true,
1146
+ onInteractOutside(event) {
1147
+ ctx2.onInteractOutside?.(event);
1148
+ if (event.defaultPrevented)
1149
+ return;
1150
+ ctx2.restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
1151
+ },
1152
+ onPointerDownOutside: ctx2.onPointerDownOutside,
1153
+ onFocusOutside: ctx2.onFocusOutside,
1154
+ onDismiss() {
1155
+ send({ type: "INTERACT_OUTSIDE" });
1156
+ }
1157
+ });
1158
+ },
1159
+ trackFormControl(ctx2, _evt, { send, initialContext }) {
1160
+ const inputEl = dom.getHiddenInputEl(ctx2);
1161
+ return trackFormControl(inputEl, {
1162
+ onFieldsetDisabledChange(disabled) {
1163
+ ctx2.fieldsetDisabled = disabled;
1164
+ },
1165
+ onFormReset() {
1166
+ send({ type: "VALUE.SET", value: initialContext.value, src: "form.reset" });
1167
+ }
1168
+ });
1169
+ },
1170
+ trackPointerMove(ctx2, _evt, { send }) {
1171
+ return trackPointerMove(dom.getDoc(ctx2), {
1172
+ onPointerMove({ point }) {
1173
+ const type = ctx2.activeId === "area" ? "AREA.POINTER_MOVE" : "CHANNEL_SLIDER.POINTER_MOVE";
1174
+ send({ type, point });
1175
+ },
1176
+ onPointerUp() {
1177
+ const type = ctx2.activeId === "area" ? "AREA.POINTER_UP" : "CHANNEL_SLIDER.POINTER_UP";
1178
+ send({ type });
1179
+ }
1180
+ });
1181
+ },
1182
+ disableTextSelection(ctx2) {
1183
+ return disableTextSelection({ doc: dom.getDoc(ctx2), target: dom.getContentEl(ctx2) });
1184
+ }
1185
+ },
1186
+ actions: {
1187
+ openEyeDropper(ctx2) {
1188
+ const isSupported = "EyeDropper" in dom.getWin(ctx2);
1189
+ if (!isSupported)
1190
+ return;
1191
+ const win = dom.getWin(ctx2);
1192
+ const picker = new win.EyeDropper();
1193
+ picker.open().then(({ sRGBHex }) => {
1194
+ const format = ctx2.value.getFormat();
1195
+ const color = parseColor4(sRGBHex).toFormat(format);
1196
+ set.value(ctx2, color);
1197
+ ctx2.onValueChangeEnd?.({ value: ctx2.value, valueAsString: ctx2.valueAsString });
1198
+ }).catch(() => void 0);
1199
+ },
1200
+ setActiveChannel(ctx2, evt) {
1201
+ ctx2.activeId = evt.id;
1202
+ if (evt.channel)
1203
+ ctx2.activeChannel = evt.channel;
1204
+ if (evt.orientation)
1205
+ ctx2.activeOrientation = evt.orientation;
1206
+ },
1207
+ clearActiveChannel(ctx2) {
1208
+ ctx2.activeChannel = null;
1209
+ ctx2.activeId = null;
1210
+ ctx2.activeOrientation = null;
1211
+ },
1212
+ setAreaColorFromPoint(ctx2, evt) {
1213
+ const { xChannel, yChannel } = evt.channel || ctx2.activeChannel;
1214
+ const percent = dom.getAreaValueFromPoint(ctx2, evt.point);
1215
+ if (!percent)
1216
+ return;
1217
+ const xValue = ctx2.areaValue.getChannelPercentValue(xChannel, percent.x);
1218
+ const yValue = ctx2.areaValue.getChannelPercentValue(yChannel, 1 - percent.y);
1219
+ const color = ctx2.areaValue.withChannelValue(xChannel, xValue).withChannelValue(yChannel, yValue);
1220
+ set.value(ctx2, color);
1221
+ },
1222
+ setChannelColorFromPoint(ctx2, evt) {
1223
+ const channel = evt.channel || ctx2.activeId;
1224
+ const percent = dom.getChannelSliderValueFromPoint(ctx2, evt.point, channel);
1225
+ if (!percent)
1226
+ return;
1227
+ const orientation = ctx2.activeOrientation || "horizontal";
1228
+ const channelPercent = orientation === "horizontal" ? percent.x : percent.y;
1229
+ const value = ctx2.areaValue.getChannelPercentValue(channel, channelPercent);
1230
+ const color = ctx2.areaValue.withChannelValue(channel, value);
1231
+ set.value(ctx2, color);
1232
+ },
1233
+ setValue(ctx2, evt) {
1234
+ set.value(ctx2, evt.value);
1235
+ },
1236
+ setFormat(ctx2, evt) {
1237
+ set.format(ctx2, evt.format);
1238
+ },
1239
+ syncInputElements(ctx2) {
1240
+ sync.inputs(ctx2);
1241
+ },
1242
+ invokeOnChangeEnd(ctx2) {
1243
+ invoke.changeEnd(ctx2);
1244
+ },
1245
+ setChannelColorFromInput(ctx2, evt) {
1246
+ const { channel, isTextField, value } = evt;
1247
+ const currentAlpha = ctx2.value.getChannelValue("alpha");
1248
+ let color;
1249
+ if (channel === "alpha") {
1250
+ let valueAsNumber = parseFloat(value);
1251
+ valueAsNumber = Number.isNaN(valueAsNumber) ? currentAlpha : valueAsNumber;
1252
+ color = ctx2.value.withChannelValue("alpha", valueAsNumber);
1253
+ } else if (isTextField) {
1254
+ color = tryCatch(
1255
+ () => parse(value).withChannelValue("alpha", currentAlpha),
1256
+ () => ctx2.value
1257
+ );
1258
+ } else {
1259
+ const current = ctx2.value.toFormat(ctx2.format);
1260
+ const valueAsNumber = Number.isNaN(value) ? current.getChannelValue(channel) : value;
1261
+ color = current.withChannelValue(channel, valueAsNumber);
1262
+ }
1263
+ sync.inputs(ctx2, color);
1264
+ set.value(ctx2, color);
1265
+ },
1266
+ incrementChannel(ctx2, evt) {
1267
+ const color = ctx2.value.incrementChannel(evt.channel, evt.step);
1268
+ set.value(ctx2, color);
1269
+ },
1270
+ decrementChannel(ctx2, evt) {
1271
+ const color = ctx2.value.decrementChannel(evt.channel, evt.step);
1272
+ set.value(ctx2, color);
1273
+ },
1274
+ incrementXChannel(ctx2, evt) {
1275
+ const { xChannel } = evt.channel;
1276
+ const color = ctx2.areaValue.incrementChannel(xChannel, evt.step);
1277
+ set.value(ctx2, color);
1278
+ },
1279
+ decrementXChannel(ctx2, evt) {
1280
+ const { xChannel } = evt.channel;
1281
+ const color = ctx2.areaValue.decrementChannel(xChannel, evt.step);
1282
+ set.value(ctx2, color);
1283
+ },
1284
+ incrementYChannel(ctx2, evt) {
1285
+ const { yChannel } = evt.channel;
1286
+ const color = ctx2.areaValue.incrementChannel(yChannel, evt.step);
1287
+ set.value(ctx2, color);
1288
+ },
1289
+ decrementYChannel(ctx2, evt) {
1290
+ const { yChannel } = evt.channel;
1291
+ const color = ctx2.areaValue.decrementChannel(yChannel, evt.step);
1292
+ set.value(ctx2, color);
1293
+ },
1294
+ setChannelToMax(ctx2, evt) {
1295
+ const range = ctx2.value.getChannelRange(evt.channel);
1296
+ const color = ctx2.value.withChannelValue(evt.channel, range.maxValue);
1297
+ set.value(ctx2, color);
1298
+ },
1299
+ setChannelToMin(ctx2, evt) {
1300
+ const range = ctx2.value.getChannelRange(evt.channel);
1301
+ const color = ctx2.value.withChannelValue(evt.channel, range.minValue);
1302
+ set.value(ctx2, color);
1303
+ },
1304
+ focusAreaThumb(ctx2) {
1305
+ raf(() => {
1306
+ dom.getAreaThumbEl(ctx2)?.focus({ preventScroll: true });
1307
+ });
1308
+ },
1309
+ focusChannelThumb(ctx2, evt) {
1310
+ raf(() => {
1311
+ dom.getChannelSliderThumbEl(ctx2, evt.channel)?.focus({ preventScroll: true });
1312
+ });
1313
+ },
1314
+ setInitialFocus(ctx2) {
1315
+ raf(() => {
1316
+ const element = getInitialFocus({
1317
+ root: dom.getContentEl(ctx2),
1318
+ getInitialEl: ctx2.initialFocusEl
1319
+ });
1320
+ element?.focus({ preventScroll: true });
1321
+ });
1322
+ },
1323
+ setReturnFocus(ctx2) {
1324
+ raf(() => {
1325
+ dom.getTriggerEl(ctx2)?.focus({ preventScroll: true });
1326
+ });
1327
+ },
1328
+ syncFormatSelectElement(ctx2) {
1329
+ sync.formatSelect(ctx2);
1330
+ },
1331
+ invokeOnOpen(ctx2) {
1332
+ ctx2.onOpenChange?.({ open: true });
1333
+ },
1334
+ invokeOnClose(ctx2) {
1335
+ ctx2.onOpenChange?.({ open: false });
1336
+ },
1337
+ toggleVisibility(ctx2, evt, { send }) {
1338
+ send({ type: ctx2.open ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE", previousEvent: evt });
1339
+ }
1340
+ },
1341
+ compareFns: {
1342
+ value: (a, b) => a.isEqual(b)
1343
+ }
1344
+ }
1345
+ );
1346
+ }
1347
+ var sync = {
1348
+ // sync channel inputs
1349
+ inputs(ctx, color) {
1350
+ const channelInputs = dom.getChannelInputEls(ctx);
1351
+ raf(() => {
1352
+ channelInputs.forEach((inputEl) => {
1353
+ const channel = inputEl.dataset.channel;
1354
+ dom.setValue(inputEl, getChannelValue(color || ctx.value, channel));
1355
+ });
1356
+ });
1357
+ },
1358
+ // sync format select
1359
+ formatSelect(ctx) {
1360
+ const selectEl = dom.getFormatSelectEl(ctx);
1361
+ raf(() => {
1362
+ dom.setValue(selectEl, ctx.format);
1363
+ });
1364
+ }
1365
+ };
1366
+ var invoke = {
1367
+ changeEnd(ctx) {
1368
+ const value = ctx.value.toFormat(ctx.format);
1369
+ ctx.onValueChangeEnd?.({
1370
+ value,
1371
+ valueAsString: ctx.valueAsString
1372
+ });
1373
+ },
1374
+ change(ctx) {
1375
+ const value = ctx.value.toFormat(ctx.format);
1376
+ ctx.onValueChange?.({
1377
+ value,
1378
+ valueAsString: ctx.valueAsString
1379
+ });
1380
+ dispatchInputValueEvent(dom.getHiddenInputEl(ctx), { value: ctx.valueAsString });
1381
+ },
1382
+ formatChange(ctx) {
1383
+ ctx.onFormatChange?.({ format: ctx.format });
1384
+ }
1385
+ };
1386
+ var set = {
1387
+ value(ctx, color) {
1388
+ if (!color || ctx.value.isEqual(color))
1389
+ return;
1390
+ ctx.value = color;
1391
+ invoke.change(ctx);
1392
+ },
1393
+ format(ctx, format) {
1394
+ if (ctx.format === format)
1395
+ return;
1396
+ ctx.format = format;
1397
+ invoke.formatChange(ctx);
1398
+ }
1399
+ };
1400
+ export {
1401
+ anatomy,
1402
+ connect,
1403
+ machine,
1404
+ parse
1405
+ };
2
1406
  //# sourceMappingURL=index.mjs.map