zds-pickers 4.0.12 → 4.0.13

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.cjs.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require("react/jsx-runtime");require("react");const e={noteOff:8,noteOn:9,aftertouch:10,controlChange:11,programChange:12,channelPressure:13,pitchWheel:14},l=15,n=240,s=[{value:e.noteOn,label:"Note On"},{value:e.noteOff,label:"Note Stack"},{value:e.controlChange,label:"Control Change"},{value:e.programChange,label:"Program Change"},{value:e.aftertouch,label:"Aftertouch"},{value:e.channelPressure,label:"Channel Pressure"},{value:e.pitchWheel,label:"Pitch Wheel"}],E=t=>{var a;return((a=s.filter(({value:o})=>o===t)[0])==null?void 0:a.label)||"???"},S=(t,a)=>t|a<<4,u=t=>({status:(t&n)>>4|8,channel:t&l}),c="__react_svg_text_measurement_id",r=0,_=1,i=2,h=3,v=4,C=5,b=6,R=7,N=[{value:R,label:"Always maxed out."},{value:b,label:"Most sensitive."},{value:C,label:"Moderately sensitive."},{value:v,label:"A little sensitive."},{value:r,label:"Linear, no change."},{value:_,label:"A little less sensitive."},{value:i,label:"Even less sensitive."},{value:h,label:"Least sensitive."}];exports.MASK_CHANNEL=l;exports.MASK_STATUS=n;exports.MEASUREMENT_ELEMENT_ID=c;exports.RESPONSE_CURVES=N;exports.Statuses=e;exports.combineStatusWithChannel=S;exports.extractStatusAndChannel=u;exports.getStatusLabel=E;exports.statusOptions=s;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require("react/jsx-runtime");require("react");const e={noteOff:8,noteOn:9,aftertouch:10,controlChange:11,programChange:12,channelPressure:13,pitchWheel:14},l=15,n=240,s=[{value:e.noteOn,label:"Note On"},{value:e.noteOff,label:"Note Stack"},{value:e.controlChange,label:"Control Change"},{value:e.programChange,label:"Program Change"},{value:e.aftertouch,label:"Aftertouch"},{value:e.channelPressure,label:"Channel Pressure"},{value:e.pitchWheel,label:"Pitch Wheel"}],u=t=>{var a;return((a=s.filter(({value:o})=>o===t)[0])==null?void 0:a.label)||"???"},E=(t,a)=>t|a<<4,c=t=>({status:(t&n)>>4|8,channel:t&l}),r=0,S=1,i=2,_=3,h=4,v=5,C=6,b=7,N=[{value:b,label:"Always maxed out."},{value:C,label:"Most sensitive."},{value:v,label:"Moderately sensitive."},{value:h,label:"A little sensitive."},{value:r,label:"Linear, no change."},{value:S,label:"A little less sensitive."},{value:i,label:"Even less sensitive."},{value:_,label:"Least sensitive."}],R="__react_svg_text_measurement_id";exports.MASK_CHANNEL=l;exports.MASK_STATUS=n;exports.MEASUREMENT_ELEMENT_ID=R;exports.Statuses=e;exports.combineStatusWithChannel=E;exports.extractStatusAndChannel=c;exports.getStatusLabel=u;exports.responseCurves=N;exports.statusOptions=s;
2
2
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../lib/midi/export.ts","../lib/other/SVGText.tsx","../lib/pickers/ResponseCurve.tsx"],"sourcesContent":["import type { Option } from 'lib/pickers/Select'\n\nconst Statuses = {\n noteOff: 8, // 1000\n noteOn: 9, // 1001\n aftertouch: 10, // 1010\n controlChange: 11, // 1011\n programChange: 12, // 1100\n channelPressure: 13, // 1101\n pitchWheel: 14, // 1110\n} as const\n\ntype Status = (typeof Statuses)[keyof typeof Statuses]\n\nconst MASK_CHANNEL = 15 // 00001111\nconst MASK_STATUS = 240 // 01110000\n\nconst statusOptions: Option<Status>[] = [\n { value: Statuses.noteOn, label: 'Note On' },\n { value: Statuses.noteOff, label: 'Note Stack' },\n { value: Statuses.controlChange, label: 'Control Change' },\n { value: Statuses.programChange, label: 'Program Change' },\n { value: Statuses.aftertouch, label: 'Aftertouch' },\n { value: Statuses.channelPressure, label: 'Channel Pressure' },\n { value: Statuses.pitchWheel, label: 'Pitch Wheel' },\n]\n\nconst getStatusLabel = (val: Status) =>\n statusOptions.filter(({ value }) => value === val)[0]?.label || '???'\n\nconst combineStatusWithChannel = (channel: number, status: Status) =>\n channel | (status << 4)\n\nconst extractStatusAndChannel = (\n status: number,\n): {\n status: Status\n channel: number\n} => ({\n status: (((status & MASK_STATUS) >> 4) | 8) as Status,\n channel: status & MASK_CHANNEL,\n})\n\nexport {\n combineStatusWithChannel,\n extractStatusAndChannel,\n getStatusLabel,\n MASK_CHANNEL,\n MASK_STATUS,\n statusOptions,\n Statuses,\n type Status,\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nconst MEASUREMENT_ELEMENT_ID = '__react_svg_text_measurement_id'\n\ntype WordsByLine = {\n words: string[]\n width: number\n showLine: boolean\n}\n\nconst calculateWordsByLines = (\n text: string,\n wordWidths: WordWidths,\n maxWidth: number,\n maxHeight: number,\n) => {\n const { lineHeight, spaceWidth, wordsWithComputedWidth } = wordWidths\n\n return text.split(/\\s+/).reduce((result: WordsByLine[], word) => {\n const wordWidth = wordsWithComputedWidth[word]\n const currentLine = result[result.length - 1]\n if (currentLine && currentLine.width + wordWidth + spaceWidth < maxWidth) {\n // Word can be added to an existing line\n currentLine.words.push(word)\n currentLine.width += wordWidth + spaceWidth\n } else {\n // Add first word to line or word is too long to scaleToFit on existing line\n const newLine: WordsByLine = {\n words: [word],\n width: wordWidth,\n showLine: maxHeight\n ? lineHeight * (result.length + 1) < maxHeight\n : true,\n }\n result.push(newLine)\n }\n return result\n }, [])\n}\n\ntype WordWidths = {\n wordsWithComputedWidth: Record<string, number>\n spaceWidth: number\n lineHeight: number\n}\n\nconst calculateWordWidths = (\n style?: CSSStyleDeclaration,\n textNode?: SVGGraphicsElement | null,\n text?: string,\n): WordWidths | undefined => {\n if (style && textNode) {\n // biome-ignore lint/complexity/noForEach: <explanation>\n Array.from(style).forEach(key =>\n textNode.style.setProperty(\n key,\n style.getPropertyValue(key),\n style.getPropertyPriority(key),\n ),\n )\n const wordArray = [...new Set(String(text).split(/\\s+/))]\n const wordsWithComputedWidth = wordArray.reduce((wordMap, word) => {\n textNode.textContent = word\n // biome-ignore lint/performance/noAccumulatingSpread: <explanation>\n return { ...wordMap, [word]: textNode.getBBox().width }\n }, {})\n\n textNode.textContent = '\\u00A0'\n\n const spaceWidth =\n (textNode as SVGTextContentElement)?.getComputedTextLength?.() || 8\n const lineHeight = textNode.getBBox().height\n\n textNode.setAttribute('style', '')\n return { wordsWithComputedWidth, spaceWidth, lineHeight }\n }\n return undefined\n}\n\ntype TextProps = Partial<HTMLOrSVGElement> & {\n className?: string\n dx?: number\n dy?: number\n maxHeight?: number\n maxWidth?: number\n transform?: string\n text: string\n textAnchor?: React.CSSProperties['textAnchor']\n verticalAnchor?: 'start' | 'middle' | 'end'\n x?: number\n y?: number\n}\n\nconst Text = (props: TextProps) => {\n const {\n className = '',\n dx = 0,\n dy = 0,\n maxHeight = 1000,\n maxWidth = 1000,\n // textAnchor = 'start',\n text = '',\n verticalAnchor = 'start',\n x = 0,\n y = 0,\n transform = '',\n ...rest\n } = props\n const [wordWidths, setWordWidths] = useState<WordWidths>()\n const [textLines, setTextLines] = useState<WordsByLine[]>([])\n const [style, setComputedStyle] = useState<CSSStyleDeclaration>()\n const measureRef = useRef<SVGSVGElement | HTMLElement>({} as HTMLElement)\n\n const displayedLines: WordsByLine[] = useMemo(() => {\n const result = textLines.filter(({ showLine }) => showLine)\n return result.length\n ? result\n : text\n .split(/\\n/)\n .map(line => ({ words: [line], width: 0, showLine: true }))\n }, [textLines, text])\n\n const ref: React.LegacyRef<SVGTextElement> = useCallback(\n (node: SVGTextElement | null) => {\n setComputedStyle(\n node !== null ? window.getComputedStyle(node) : undefined,\n )\n },\n [],\n )\n\n useEffect(() => {\n const el = document.getElementById(MEASUREMENT_ELEMENT_ID)\n if (el === null) {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n svg.setAttribute('id', MEASUREMENT_ELEMENT_ID)\n document.body.appendChild(svg)\n svg.appendChild(\n document.createElementNS('http://www.w3.org/2000/svg', 'text'),\n )\n measureRef.current = svg\n return () => {\n document.body.removeChild(svg)\n }\n }\n measureRef.current = el\n }, [])\n\n useEffect(() => {\n const wordWithWidths = calculateWordWidths(\n style,\n measureRef.current as SVGGraphicsElement | null,\n text,\n )\n\n setWordWidths(wordWithWidths)\n }, [text, style])\n\n useEffect(() => {\n if (maxWidth && wordWidths) {\n const lines = text\n .split(/\\n/)\n .flatMap(line =>\n calculateWordsByLines(line, wordWidths, maxWidth, maxHeight),\n )\n\n setTextLines(lines)\n }\n }, [maxHeight, maxWidth, wordWidths, text])\n\n const startDy = useMemo(() => {\n if (wordWidths?.lineHeight) {\n switch (verticalAnchor) {\n case 'start':\n return wordWidths.lineHeight\n\n case 'middle':\n return -(((displayedLines.length - 1) * wordWidths.lineHeight) / 2)\n\n default:\n return -(displayedLines.length - 1) * wordWidths.lineHeight\n }\n }\n return 0\n }, [displayedLines.length, verticalAnchor, wordWidths?.lineHeight])\n\n return (\n <text\n className={className}\n ref={ref}\n dx={dx}\n dy={dy}\n x={x}\n y={y}\n // textAnchor={textAnchor}\n transform={transform}\n {...rest}>\n <>\n {displayedLines.map((line, idx) => (\n <tspan\n dx={x + dx}\n dy={idx === 0 ? startDy + dy : wordWidths?.lineHeight || 0}\n key={idx}\n x={0}>\n {line.words.join(' ')}\n </tspan>\n ))}\n {textLines.length && displayedLines.length !== textLines.length && (\n <>\n <tspan>...</tspan>\n <title>{text}</title>\n </>\n )}\n </>\n </text>\n )\n}\n\nexport default Text\n\nexport { MEASUREMENT_ELEMENT_ID }\n\nexport type { TextProps, WordWidths, WordsByLine }\n","import { useRef } from 'react'\nimport useComponentSize from '../hooks/useComponentSize'\nimport DefaultTooltip, { type TooltipProps } from '../other/DefaultTooltip'\nimport SVGText from '../other/SVGText'\nimport type { Option } from './Select'\n\nconst RESPONSE_CURVE_0 = 0\nconst RESPONSE_CURVE_1 = 1\nconst RESPONSE_CURVE_2 = 2\nconst RESPONSE_CURVE_3 = 3\nconst RESPONSE_CURVE_4 = 4\nconst RESPONSE_CURVE_5 = 5\nconst RESPONSE_CURVE_6 = 6\nconst RESPONSE_CURVE_7 = 7\n\ntype Curve =\n | typeof RESPONSE_CURVE_0\n | typeof RESPONSE_CURVE_1\n | typeof RESPONSE_CURVE_2\n | typeof RESPONSE_CURVE_3\n | typeof RESPONSE_CURVE_4\n | typeof RESPONSE_CURVE_5\n | typeof RESPONSE_CURVE_6\n | typeof RESPONSE_CURVE_7\n\ntype ResponseCurve = {\n value: Curve\n label: React.ReactNode\n c1: number\n c2: number\n x1: number\n y1: number\n x2: number\n y2: number\n labelX: number\n labelY: number\n}\n\nconst RESPONSE_CURVES: Option<Curve>[] = [\n {\n value: RESPONSE_CURVE_7,\n label: 'Always maxed out.',\n },\n {\n value: RESPONSE_CURVE_6,\n label: 'Most sensitive.',\n },\n {\n value: RESPONSE_CURVE_5,\n label: 'Moderately sensitive.',\n },\n {\n value: RESPONSE_CURVE_4,\n label: 'A little sensitive.',\n },\n {\n value: RESPONSE_CURVE_0,\n label: 'Linear, no change.',\n },\n {\n value: RESPONSE_CURVE_1,\n label: 'A little less sensitive.',\n },\n {\n value: RESPONSE_CURVE_2,\n label: 'Even less sensitive.',\n },\n {\n value: RESPONSE_CURVE_3,\n label: 'Least sensitive.',\n },\n]\n\n// const width = 218\n// const height = 150\nconst axisOffset = 20\nconst buttonSize = 15\n\nconst axisX1 = axisOffset\nconst axisY1 = axisOffset\n\ntype ResponseCurveProps = {\n autosize: boolean\n disabled?: boolean\n inverted: boolean\n onChange: (event: { target: { value: Curve } }) => void\n Tooltip: React.FC<TooltipProps>\n value: Curve\n}\n\nconst ResponseCurve = (props: ResponseCurveProps) => {\n const {\n Tooltip = DefaultTooltip,\n autosize,\n disabled,\n inverted,\n onChange,\n value: responseCurve,\n } = props\n\n const ref = useRef(null)\n const svgRef = useRef(null)\n const { height: ourHeight, width: ourWidth } = useComponentSize(ref)\n\n const width = autosize ? ourWidth || 218 : 218\n const height = autosize ? ourHeight || 150 : 150\n\n const axisX2 = width - axisOffset\n const axisY2 = height - axisOffset\n\n const xMid = width / 2\n const yMid = height / 2\n\n const svgProps = { ref: svgRef }\n\n const responseCurves = RESPONSE_CURVES.map(\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: <explanation>\n ({ value, label }): ResponseCurve => {\n let c1 = 0\n let c2 = 0\n let x1 = axisX1\n let y1 = inverted ? axisY1 : axisY2\n let x2 = axisX2\n let y2 = inverted ? axisY2 : axisY1\n let labelX = xMid\n let labelY = yMid\n switch (value) {\n case RESPONSE_CURVE_0:\n c1 = xMid\n c2 = yMid\n labelY += 3\n\n break\n case RESPONSE_CURVE_1:\n c1 = inverted ? xMid + width * 0.13 : xMid - width * 0.13\n c2 = yMid - height * 0.13\n labelX = inverted ? xMid + width * 0.1 : xMid - width * 0.1\n labelY = yMid - height * 0.09\n break\n\n case RESPONSE_CURVE_2:\n c1 = inverted ? xMid + width * 0.25 : xMid - width * 0.25\n c2 = yMid - height * 0.25\n labelX = inverted ? xMid + width * 0.2 : xMid - width * 0.2\n labelY = yMid - height * 0.17\n break\n\n case RESPONSE_CURVE_3:\n c1 = inverted ? xMid + width * 0.35 : xMid - width * 0.35\n c2 = yMid - height * 0.35\n labelX = inverted ? xMid + width * 0.28 : xMid - width * 0.28\n labelY = yMid - height * 0.25\n break\n\n case RESPONSE_CURVE_4:\n c1 = inverted ? xMid - width * 0.13 : xMid + width * 0.13\n c2 = yMid + height * 0.13\n labelX = inverted ? xMid - width * 0.1 : xMid + width * 0.1\n labelY = yMid + height * 0.1\n break\n\n case RESPONSE_CURVE_5:\n c1 = inverted ? xMid - width * 0.25 : xMid + width * 0.25\n c2 = yMid + height * 0.25\n labelX = inverted ? xMid - width * 0.2 : xMid + width * 0.2\n labelY = yMid + height * 0.18\n break\n\n case RESPONSE_CURVE_6:\n c1 = inverted ? xMid - width * 0.35 : xMid + width * 0.35\n c2 = yMid + height * 0.35\n labelX = inverted ? xMid - width * 0.28 : xMid + width * 0.28\n labelY = yMid + height * 0.25\n break\n\n case RESPONSE_CURVE_7:\n x1 = inverted ? axisX1 : axisX2\n y1 = axisY1\n x2 = x1\n y2 = axisY2\n c1 = x1\n c2 = yMid\n labelX = x1 - 5\n labelY = height - 30\n break\n\n default:\n break\n }\n return {\n value,\n label,\n c1,\n c2,\n x1,\n y1,\n x2,\n y2,\n labelX,\n labelY,\n }\n },\n )\n\n return (\n <div\n className=\"response-curve-picker\"\n ref={ref}>\n <svg {...svgProps}>\n <rect\n className=\"container\"\n height={height}\n rx={3}\n ry={3}\n width={width}\n x={0}\n y={0}\n />\n\n <SVGText\n className=\"axis\"\n textAnchor=\"middle\"\n transform={`translate(${axisX1 - 14} ${height / 2}) rotate(90)`}\n x={0}\n y={0}\n text=\"Applied force\"\n />\n\n <SVGText\n className=\"axis\"\n textAnchor=\"middle\"\n transform={`translate(${width / 2} ${axisY2 + 13})`}\n x={0}\n y={0}\n text=\"Output (velocity)\"\n />\n\n <line\n className=\"axis\"\n x1={axisX1}\n x2={axisX1}\n y1={axisY1}\n y2={axisY2}\n />\n <line\n className=\"axis\"\n x1={axisX1}\n x2={axisX2}\n y1={axisY2}\n y2={axisY2}\n />\n\n {responseCurves.map(\n ({ value, label, x1, y1, x2, y2, c1, c2, labelX, labelY }) => (\n <g key={value}>\n <path\n className={value === responseCurve ? 'curve-selected' : 'curve'}\n d={`M${x1} ${y1} C ${c1} ${c2}, ${c1} ${c2}, ${x2} ${y2}`}\n />\n\n <Tooltip\n placement=\"left\"\n title={label}>\n <rect\n className={\n value === responseCurve ? 'button-selected' : 'button'\n }\n height={buttonSize}\n onClick={\n disabled\n ? f => f\n : () =>\n onChange({\n target: {\n value: Number.parseInt(String(value)) as Curve,\n },\n })\n }\n transform={`translate(${labelX + 3} ${labelY - buttonSize / 1.05}) rotate(45)`}\n width={buttonSize}\n />\n </Tooltip>\n\n <text\n className={\n value === responseCurve ? 'button-selected' : 'button'\n }\n transform={`translate(${labelX} ${labelY})`}>\n {value}\n <title>{label}</title>\n </text>\n </g>\n ),\n )}\n </svg>\n </div>\n )\n}\n\nexport default ResponseCurve\n\nexport { RESPONSE_CURVES }\n\nexport type { Curve, ResponseCurve, ResponseCurveProps }\n"],"names":["Statuses","MASK_CHANNEL","MASK_STATUS","statusOptions","getStatusLabel","val","_a","value","combineStatusWithChannel","channel","status","extractStatusAndChannel","MEASUREMENT_ELEMENT_ID","RESPONSE_CURVE_0","RESPONSE_CURVE_1","RESPONSE_CURVE_2","RESPONSE_CURVE_3","RESPONSE_CURVE_4","RESPONSE_CURVE_5","RESPONSE_CURVE_6","RESPONSE_CURVE_7","RESPONSE_CURVES"],"mappings":"8HAEA,MAAMA,EAAW,CACf,QAAS,EACT,OAAQ,EACR,WAAY,GACZ,cAAe,GACf,cAAe,GACf,gBAAiB,GACjB,WAAY,EACd,EAIMC,EAAe,GACfC,EAAc,IAEdC,EAAkC,CACtC,CAAE,MAAOH,EAAS,OAAQ,MAAO,SAAU,EAC3C,CAAE,MAAOA,EAAS,QAAS,MAAO,YAAa,EAC/C,CAAE,MAAOA,EAAS,cAAe,MAAO,gBAAiB,EACzD,CAAE,MAAOA,EAAS,cAAe,MAAO,gBAAiB,EACzD,CAAE,MAAOA,EAAS,WAAY,MAAO,YAAa,EAClD,CAAE,MAAOA,EAAS,gBAAiB,MAAO,kBAAmB,EAC7D,CAAE,MAAOA,EAAS,WAAY,MAAO,aAAc,CACrD,EAEMI,EAAkBC,UACtB,QAAAC,EAAAH,EAAc,OAAO,CAAC,CAAE,MAAAI,CAAM,IAAMA,IAAUF,CAAG,EAAE,CAAC,IAApD,YAAAC,EAAuD,QAAS,OAE5DE,EAA2B,CAACC,EAAiBC,IACjDD,EAAWC,GAAU,EAEjBC,EACJD,IAII,CACJ,QAAWA,EAASR,IAAgB,EAAK,EACzC,QAASQ,EAAST,CACpB,GCvCMW,EAAyB,kCCIzBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EAyBnBC,EAAmC,CACvC,CACE,MAAOD,EACP,MAAO,mBACT,EACA,CACE,MAAOD,EACP,MAAO,iBACT,EACA,CACE,MAAOD,EACP,MAAO,uBACT,EACA,CACE,MAAOD,EACP,MAAO,qBACT,EACA,CACE,MAAOJ,EACP,MAAO,oBACT,EACA,CACE,MAAOC,EACP,MAAO,0BACT,EACA,CACE,MAAOC,EACP,MAAO,sBACT,EACA,CACE,MAAOC,EACP,MAAO,kBAAA,CAEX"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../lib/midi/export.ts","../lib/other/SVGText.tsx"],"sourcesContent":["import type { Option } from 'lib/pickers/Select'\n\nconst Statuses = {\n noteOff: 8, // 1000\n noteOn: 9, // 1001\n aftertouch: 10, // 1010\n controlChange: 11, // 1011\n programChange: 12, // 1100\n channelPressure: 13, // 1101\n pitchWheel: 14, // 1110\n} as const\n\ntype Status = (typeof Statuses)[keyof typeof Statuses]\n\nconst MASK_CHANNEL = 15 // 00001111\nconst MASK_STATUS = 240 // 01110000\n\nconst statusOptions: Option<Status>[] = [\n { value: Statuses.noteOn, label: 'Note On' },\n { value: Statuses.noteOff, label: 'Note Stack' },\n { value: Statuses.controlChange, label: 'Control Change' },\n { value: Statuses.programChange, label: 'Program Change' },\n { value: Statuses.aftertouch, label: 'Aftertouch' },\n { value: Statuses.channelPressure, label: 'Channel Pressure' },\n { value: Statuses.pitchWheel, label: 'Pitch Wheel' },\n]\n\nconst getStatusLabel = (val: Status) =>\n statusOptions.filter(({ value }) => value === val)[0]?.label || '???'\n\nconst combineStatusWithChannel = (channel: number, status: Status) =>\n channel | (status << 4)\n\nconst extractStatusAndChannel = (\n status: number,\n): {\n status: Status\n channel: number\n} => ({\n status: (((status & MASK_STATUS) >> 4) | 8) as Status,\n channel: status & MASK_CHANNEL,\n})\n\nconst RESPONSE_CURVE_0 = 0\nconst RESPONSE_CURVE_1 = 1\nconst RESPONSE_CURVE_2 = 2\nconst RESPONSE_CURVE_3 = 3\nconst RESPONSE_CURVE_4 = 4\nconst RESPONSE_CURVE_5 = 5\nconst RESPONSE_CURVE_6 = 6\nconst RESPONSE_CURVE_7 = 7\n\ntype Curve =\n | typeof RESPONSE_CURVE_0\n | typeof RESPONSE_CURVE_1\n | typeof RESPONSE_CURVE_2\n | typeof RESPONSE_CURVE_3\n | typeof RESPONSE_CURVE_4\n | typeof RESPONSE_CURVE_5\n | typeof RESPONSE_CURVE_6\n | typeof RESPONSE_CURVE_7\n\nconst responseCurves: Option<Curve>[] = [\n {\n value: RESPONSE_CURVE_7,\n label: 'Always maxed out.',\n },\n {\n value: RESPONSE_CURVE_6,\n label: 'Most sensitive.',\n },\n {\n value: RESPONSE_CURVE_5,\n label: 'Moderately sensitive.',\n },\n {\n value: RESPONSE_CURVE_4,\n label: 'A little sensitive.',\n },\n {\n value: RESPONSE_CURVE_0,\n label: 'Linear, no change.',\n },\n {\n value: RESPONSE_CURVE_1,\n label: 'A little less sensitive.',\n },\n {\n value: RESPONSE_CURVE_2,\n label: 'Even less sensitive.',\n },\n {\n value: RESPONSE_CURVE_3,\n label: 'Least sensitive.',\n },\n]\n\nexport {\n combineStatusWithChannel,\n extractStatusAndChannel,\n getStatusLabel,\n MASK_CHANNEL,\n MASK_STATUS,\n responseCurves,\n Statuses,\n statusOptions,\n}\n\nexport type { Curve, Status }\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nconst MEASUREMENT_ELEMENT_ID = '__react_svg_text_measurement_id'\n\ntype WordsByLine = {\n words: string[]\n width: number\n showLine: boolean\n}\n\nconst calculateWordsByLines = (\n text: string,\n wordWidths: WordWidths,\n maxWidth: number,\n maxHeight: number,\n) => {\n const { lineHeight, spaceWidth, wordsWithComputedWidth } = wordWidths\n\n return text.split(/\\s+/).reduce((result: WordsByLine[], word) => {\n const wordWidth = wordsWithComputedWidth[word]\n const currentLine = result[result.length - 1]\n if (currentLine && currentLine.width + wordWidth + spaceWidth < maxWidth) {\n // Word can be added to an existing line\n currentLine.words.push(word)\n currentLine.width += wordWidth + spaceWidth\n } else {\n // Add first word to line or word is too long to scaleToFit on existing line\n const newLine: WordsByLine = {\n words: [word],\n width: wordWidth,\n showLine: maxHeight\n ? lineHeight * (result.length + 1) < maxHeight\n : true,\n }\n result.push(newLine)\n }\n return result\n }, [])\n}\n\ntype WordWidths = {\n wordsWithComputedWidth: Record<string, number>\n spaceWidth: number\n lineHeight: number\n}\n\nconst calculateWordWidths = (\n style?: CSSStyleDeclaration,\n textNode?: SVGGraphicsElement | null,\n text?: string,\n): WordWidths | undefined => {\n if (style && textNode) {\n // biome-ignore lint/complexity/noForEach: <explanation>\n Array.from(style).forEach(key =>\n textNode.style.setProperty(\n key,\n style.getPropertyValue(key),\n style.getPropertyPriority(key),\n ),\n )\n const wordArray = [...new Set(String(text).split(/\\s+/))]\n const wordsWithComputedWidth = wordArray.reduce((wordMap, word) => {\n textNode.textContent = word\n // biome-ignore lint/performance/noAccumulatingSpread: <explanation>\n return { ...wordMap, [word]: textNode.getBBox().width }\n }, {})\n\n textNode.textContent = '\\u00A0'\n\n const spaceWidth =\n (textNode as SVGTextContentElement)?.getComputedTextLength?.() || 8\n const lineHeight = textNode.getBBox().height\n\n textNode.setAttribute('style', '')\n return { wordsWithComputedWidth, spaceWidth, lineHeight }\n }\n return undefined\n}\n\ntype TextProps = Partial<HTMLOrSVGElement> & {\n className?: string\n dx?: number\n dy?: number\n maxHeight?: number\n maxWidth?: number\n transform?: string\n text: string\n textAnchor?: React.CSSProperties['textAnchor']\n verticalAnchor?: 'start' | 'middle' | 'end'\n x?: number\n y?: number\n}\n\nconst Text = (props: TextProps) => {\n const {\n className = '',\n dx = 0,\n dy = 0,\n maxHeight = 1000,\n maxWidth = 1000,\n // textAnchor = 'start',\n text = '',\n verticalAnchor = 'start',\n x = 0,\n y = 0,\n transform = '',\n ...rest\n } = props\n const [wordWidths, setWordWidths] = useState<WordWidths>()\n const [textLines, setTextLines] = useState<WordsByLine[]>([])\n const [style, setComputedStyle] = useState<CSSStyleDeclaration>()\n const measureRef = useRef<SVGSVGElement | HTMLElement>({} as HTMLElement)\n\n const displayedLines: WordsByLine[] = useMemo(() => {\n const result = textLines.filter(({ showLine }) => showLine)\n return result.length\n ? result\n : text\n .split(/\\n/)\n .map(line => ({ words: [line], width: 0, showLine: true }))\n }, [textLines, text])\n\n const ref: React.LegacyRef<SVGTextElement> = useCallback(\n (node: SVGTextElement | null) => {\n setComputedStyle(\n node !== null ? window.getComputedStyle(node) : undefined,\n )\n },\n [],\n )\n\n useEffect(() => {\n const el = document.getElementById(MEASUREMENT_ELEMENT_ID)\n if (el === null) {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n svg.setAttribute('id', MEASUREMENT_ELEMENT_ID)\n document.body.appendChild(svg)\n svg.appendChild(\n document.createElementNS('http://www.w3.org/2000/svg', 'text'),\n )\n measureRef.current = svg\n return () => {\n document.body.removeChild(svg)\n }\n }\n measureRef.current = el\n }, [])\n\n useEffect(() => {\n const wordWithWidths = calculateWordWidths(\n style,\n measureRef.current as SVGGraphicsElement | null,\n text,\n )\n\n setWordWidths(wordWithWidths)\n }, [text, style])\n\n useEffect(() => {\n if (maxWidth && wordWidths) {\n const lines = text\n .split(/\\n/)\n .flatMap(line =>\n calculateWordsByLines(line, wordWidths, maxWidth, maxHeight),\n )\n\n setTextLines(lines)\n }\n }, [maxHeight, maxWidth, wordWidths, text])\n\n const startDy = useMemo(() => {\n if (wordWidths?.lineHeight) {\n switch (verticalAnchor) {\n case 'start':\n return wordWidths.lineHeight\n\n case 'middle':\n return -(((displayedLines.length - 1) * wordWidths.lineHeight) / 2)\n\n default:\n return -(displayedLines.length - 1) * wordWidths.lineHeight\n }\n }\n return 0\n }, [displayedLines.length, verticalAnchor, wordWidths?.lineHeight])\n\n return (\n <text\n className={className}\n ref={ref}\n dx={dx}\n dy={dy}\n x={x}\n y={y}\n // textAnchor={textAnchor}\n transform={transform}\n {...rest}>\n <>\n {displayedLines.map((line, idx) => (\n <tspan\n dx={x + dx}\n dy={idx === 0 ? startDy + dy : wordWidths?.lineHeight || 0}\n key={idx}\n x={0}>\n {line.words.join(' ')}\n </tspan>\n ))}\n {textLines.length && displayedLines.length !== textLines.length && (\n <>\n <tspan>...</tspan>\n <title>{text}</title>\n </>\n )}\n </>\n </text>\n )\n}\n\nexport default Text\n\nexport { MEASUREMENT_ELEMENT_ID }\n\nexport type { TextProps, WordWidths, WordsByLine }\n"],"names":["Statuses","MASK_CHANNEL","MASK_STATUS","statusOptions","getStatusLabel","val","_a","value","combineStatusWithChannel","channel","status","extractStatusAndChannel","RESPONSE_CURVE_0","RESPONSE_CURVE_1","RESPONSE_CURVE_2","RESPONSE_CURVE_3","RESPONSE_CURVE_4","RESPONSE_CURVE_5","RESPONSE_CURVE_6","RESPONSE_CURVE_7","responseCurves","MEASUREMENT_ELEMENT_ID"],"mappings":"8HAEA,MAAMA,EAAW,CACf,QAAS,EACT,OAAQ,EACR,WAAY,GACZ,cAAe,GACf,cAAe,GACf,gBAAiB,GACjB,WAAY,EACd,EAIMC,EAAe,GACfC,EAAc,IAEdC,EAAkC,CACtC,CAAE,MAAOH,EAAS,OAAQ,MAAO,SAAU,EAC3C,CAAE,MAAOA,EAAS,QAAS,MAAO,YAAa,EAC/C,CAAE,MAAOA,EAAS,cAAe,MAAO,gBAAiB,EACzD,CAAE,MAAOA,EAAS,cAAe,MAAO,gBAAiB,EACzD,CAAE,MAAOA,EAAS,WAAY,MAAO,YAAa,EAClD,CAAE,MAAOA,EAAS,gBAAiB,MAAO,kBAAmB,EAC7D,CAAE,MAAOA,EAAS,WAAY,MAAO,aAAc,CACrD,EAEMI,EAAkBC,UACtB,QAAAC,EAAAH,EAAc,OAAO,CAAC,CAAE,MAAAI,CAAM,IAAMA,IAAUF,CAAG,EAAE,CAAC,IAApD,YAAAC,EAAuD,QAAS,OAE5DE,EAA2B,CAACC,EAAiBC,IACjDD,EAAWC,GAAU,EAEjBC,EACJD,IAII,CACJ,QAAWA,EAASR,IAAgB,EAAK,EACzC,QAASQ,EAAST,CACpB,GAEMW,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EACnBC,EAAmB,EAYnBC,EAAkC,CACtC,CACE,MAAOD,EACP,MAAO,mBACT,EACA,CACE,MAAOD,EACP,MAAO,iBACT,EACA,CACE,MAAOD,EACP,MAAO,uBACT,EACA,CACE,MAAOD,EACP,MAAO,qBACT,EACA,CACE,MAAOJ,EACP,MAAO,oBACT,EACA,CACE,MAAOC,EACP,MAAO,0BACT,EACA,CACE,MAAOC,EACP,MAAO,sBACT,EACA,CACE,MAAOC,EACP,MAAO,kBAAA,CAEX,EC7FMM,EAAyB"}
package/dist/index.es.js CHANGED
@@ -23,15 +23,15 @@ const e = {
23
23
  { value: e.aftertouch, label: "Aftertouch" },
24
24
  { value: e.channelPressure, label: "Channel Pressure" },
25
25
  { value: e.pitchWheel, label: "Pitch Wheel" }
26
- ], R = (t) => {
26
+ ], b = (t) => {
27
27
  var l;
28
28
  return ((l = o.filter(({ value: a }) => a === t)[0]) == null ? void 0 : l.label) || "???";
29
- }, b = (t, l) => t | l << 4, N = (t) => ({
29
+ }, R = (t, l) => t | l << 4, N = (t) => ({
30
30
  status: (t & s) >> 4 | 8,
31
31
  channel: t & n
32
- }), O = "__react_svg_text_measurement_id", E = 0, c = 1, S = 2, u = 3, r = 4, _ = 5, i = 6, h = 7, P = [
32
+ }), c = 0, E = 1, r = 2, u = 3, S = 4, _ = 5, i = 6, v = 7, O = [
33
33
  {
34
- value: h,
34
+ value: v,
35
35
  label: "Always maxed out."
36
36
  },
37
37
  {
@@ -43,35 +43,35 @@ const e = {
43
43
  label: "Moderately sensitive."
44
44
  },
45
45
  {
46
- value: r,
46
+ value: S,
47
47
  label: "A little sensitive."
48
48
  },
49
49
  {
50
- value: E,
50
+ value: c,
51
51
  label: "Linear, no change."
52
52
  },
53
53
  {
54
- value: c,
54
+ value: E,
55
55
  label: "A little less sensitive."
56
56
  },
57
57
  {
58
- value: S,
58
+ value: r,
59
59
  label: "Even less sensitive."
60
60
  },
61
61
  {
62
62
  value: u,
63
63
  label: "Least sensitive."
64
64
  }
65
- ];
65
+ ], P = "__react_svg_text_measurement_id";
66
66
  export {
67
67
  n as MASK_CHANNEL,
68
68
  s as MASK_STATUS,
69
- O as MEASUREMENT_ELEMENT_ID,
70
- P as RESPONSE_CURVES,
69
+ P as MEASUREMENT_ELEMENT_ID,
71
70
  e as Statuses,
72
- b as combineStatusWithChannel,
71
+ R as combineStatusWithChannel,
73
72
  N as extractStatusAndChannel,
74
- R as getStatusLabel,
73
+ b as getStatusLabel,
74
+ O as responseCurves,
75
75
  o as statusOptions
76
76
  };
77
77
  //# sourceMappingURL=index.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../lib/midi/export.ts","../lib/other/SVGText.tsx","../lib/pickers/ResponseCurve.tsx"],"sourcesContent":["import type { Option } from 'lib/pickers/Select'\n\nconst Statuses = {\n noteOff: 8, // 1000\n noteOn: 9, // 1001\n aftertouch: 10, // 1010\n controlChange: 11, // 1011\n programChange: 12, // 1100\n channelPressure: 13, // 1101\n pitchWheel: 14, // 1110\n} as const\n\ntype Status = (typeof Statuses)[keyof typeof Statuses]\n\nconst MASK_CHANNEL = 15 // 00001111\nconst MASK_STATUS = 240 // 01110000\n\nconst statusOptions: Option<Status>[] = [\n { value: Statuses.noteOn, label: 'Note On' },\n { value: Statuses.noteOff, label: 'Note Stack' },\n { value: Statuses.controlChange, label: 'Control Change' },\n { value: Statuses.programChange, label: 'Program Change' },\n { value: Statuses.aftertouch, label: 'Aftertouch' },\n { value: Statuses.channelPressure, label: 'Channel Pressure' },\n { value: Statuses.pitchWheel, label: 'Pitch Wheel' },\n]\n\nconst getStatusLabel = (val: Status) =>\n statusOptions.filter(({ value }) => value === val)[0]?.label || '???'\n\nconst combineStatusWithChannel = (channel: number, status: Status) =>\n channel | (status << 4)\n\nconst extractStatusAndChannel = (\n status: number,\n): {\n status: Status\n channel: number\n} => ({\n status: (((status & MASK_STATUS) >> 4) | 8) as Status,\n channel: status & MASK_CHANNEL,\n})\n\nexport {\n combineStatusWithChannel,\n extractStatusAndChannel,\n getStatusLabel,\n MASK_CHANNEL,\n MASK_STATUS,\n statusOptions,\n Statuses,\n type Status,\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nconst MEASUREMENT_ELEMENT_ID = '__react_svg_text_measurement_id'\n\ntype WordsByLine = {\n words: string[]\n width: number\n showLine: boolean\n}\n\nconst calculateWordsByLines = (\n text: string,\n wordWidths: WordWidths,\n maxWidth: number,\n maxHeight: number,\n) => {\n const { lineHeight, spaceWidth, wordsWithComputedWidth } = wordWidths\n\n return text.split(/\\s+/).reduce((result: WordsByLine[], word) => {\n const wordWidth = wordsWithComputedWidth[word]\n const currentLine = result[result.length - 1]\n if (currentLine && currentLine.width + wordWidth + spaceWidth < maxWidth) {\n // Word can be added to an existing line\n currentLine.words.push(word)\n currentLine.width += wordWidth + spaceWidth\n } else {\n // Add first word to line or word is too long to scaleToFit on existing line\n const newLine: WordsByLine = {\n words: [word],\n width: wordWidth,\n showLine: maxHeight\n ? lineHeight * (result.length + 1) < maxHeight\n : true,\n }\n result.push(newLine)\n }\n return result\n }, [])\n}\n\ntype WordWidths = {\n wordsWithComputedWidth: Record<string, number>\n spaceWidth: number\n lineHeight: number\n}\n\nconst calculateWordWidths = (\n style?: CSSStyleDeclaration,\n textNode?: SVGGraphicsElement | null,\n text?: string,\n): WordWidths | undefined => {\n if (style && textNode) {\n // biome-ignore lint/complexity/noForEach: <explanation>\n Array.from(style).forEach(key =>\n textNode.style.setProperty(\n key,\n style.getPropertyValue(key),\n style.getPropertyPriority(key),\n ),\n )\n const wordArray = [...new Set(String(text).split(/\\s+/))]\n const wordsWithComputedWidth = wordArray.reduce((wordMap, word) => {\n textNode.textContent = word\n // biome-ignore lint/performance/noAccumulatingSpread: <explanation>\n return { ...wordMap, [word]: textNode.getBBox().width }\n }, {})\n\n textNode.textContent = '\\u00A0'\n\n const spaceWidth =\n (textNode as SVGTextContentElement)?.getComputedTextLength?.() || 8\n const lineHeight = textNode.getBBox().height\n\n textNode.setAttribute('style', '')\n return { wordsWithComputedWidth, spaceWidth, lineHeight }\n }\n return undefined\n}\n\ntype TextProps = Partial<HTMLOrSVGElement> & {\n className?: string\n dx?: number\n dy?: number\n maxHeight?: number\n maxWidth?: number\n transform?: string\n text: string\n textAnchor?: React.CSSProperties['textAnchor']\n verticalAnchor?: 'start' | 'middle' | 'end'\n x?: number\n y?: number\n}\n\nconst Text = (props: TextProps) => {\n const {\n className = '',\n dx = 0,\n dy = 0,\n maxHeight = 1000,\n maxWidth = 1000,\n // textAnchor = 'start',\n text = '',\n verticalAnchor = 'start',\n x = 0,\n y = 0,\n transform = '',\n ...rest\n } = props\n const [wordWidths, setWordWidths] = useState<WordWidths>()\n const [textLines, setTextLines] = useState<WordsByLine[]>([])\n const [style, setComputedStyle] = useState<CSSStyleDeclaration>()\n const measureRef = useRef<SVGSVGElement | HTMLElement>({} as HTMLElement)\n\n const displayedLines: WordsByLine[] = useMemo(() => {\n const result = textLines.filter(({ showLine }) => showLine)\n return result.length\n ? result\n : text\n .split(/\\n/)\n .map(line => ({ words: [line], width: 0, showLine: true }))\n }, [textLines, text])\n\n const ref: React.LegacyRef<SVGTextElement> = useCallback(\n (node: SVGTextElement | null) => {\n setComputedStyle(\n node !== null ? window.getComputedStyle(node) : undefined,\n )\n },\n [],\n )\n\n useEffect(() => {\n const el = document.getElementById(MEASUREMENT_ELEMENT_ID)\n if (el === null) {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n svg.setAttribute('id', MEASUREMENT_ELEMENT_ID)\n document.body.appendChild(svg)\n svg.appendChild(\n document.createElementNS('http://www.w3.org/2000/svg', 'text'),\n )\n measureRef.current = svg\n return () => {\n document.body.removeChild(svg)\n }\n }\n measureRef.current = el\n }, [])\n\n useEffect(() => {\n const wordWithWidths = calculateWordWidths(\n style,\n measureRef.current as SVGGraphicsElement | null,\n text,\n )\n\n setWordWidths(wordWithWidths)\n }, [text, style])\n\n useEffect(() => {\n if (maxWidth && wordWidths) {\n const lines = text\n .split(/\\n/)\n .flatMap(line =>\n calculateWordsByLines(line, wordWidths, maxWidth, maxHeight),\n )\n\n setTextLines(lines)\n }\n }, [maxHeight, maxWidth, wordWidths, text])\n\n const startDy = useMemo(() => {\n if (wordWidths?.lineHeight) {\n switch (verticalAnchor) {\n case 'start':\n return wordWidths.lineHeight\n\n case 'middle':\n return -(((displayedLines.length - 1) * wordWidths.lineHeight) / 2)\n\n default:\n return -(displayedLines.length - 1) * wordWidths.lineHeight\n }\n }\n return 0\n }, [displayedLines.length, verticalAnchor, wordWidths?.lineHeight])\n\n return (\n <text\n className={className}\n ref={ref}\n dx={dx}\n dy={dy}\n x={x}\n y={y}\n // textAnchor={textAnchor}\n transform={transform}\n {...rest}>\n <>\n {displayedLines.map((line, idx) => (\n <tspan\n dx={x + dx}\n dy={idx === 0 ? startDy + dy : wordWidths?.lineHeight || 0}\n key={idx}\n x={0}>\n {line.words.join(' ')}\n </tspan>\n ))}\n {textLines.length && displayedLines.length !== textLines.length && (\n <>\n <tspan>...</tspan>\n <title>{text}</title>\n </>\n )}\n </>\n </text>\n )\n}\n\nexport default Text\n\nexport { MEASUREMENT_ELEMENT_ID }\n\nexport type { TextProps, WordWidths, WordsByLine }\n","import { useRef } from 'react'\nimport useComponentSize from '../hooks/useComponentSize'\nimport DefaultTooltip, { type TooltipProps } from '../other/DefaultTooltip'\nimport SVGText from '../other/SVGText'\nimport type { Option } from './Select'\n\nconst RESPONSE_CURVE_0 = 0\nconst RESPONSE_CURVE_1 = 1\nconst RESPONSE_CURVE_2 = 2\nconst RESPONSE_CURVE_3 = 3\nconst RESPONSE_CURVE_4 = 4\nconst RESPONSE_CURVE_5 = 5\nconst RESPONSE_CURVE_6 = 6\nconst RESPONSE_CURVE_7 = 7\n\ntype Curve =\n | typeof RESPONSE_CURVE_0\n | typeof RESPONSE_CURVE_1\n | typeof RESPONSE_CURVE_2\n | typeof RESPONSE_CURVE_3\n | typeof RESPONSE_CURVE_4\n | typeof RESPONSE_CURVE_5\n | typeof RESPONSE_CURVE_6\n | typeof RESPONSE_CURVE_7\n\ntype ResponseCurve = {\n value: Curve\n label: React.ReactNode\n c1: number\n c2: number\n x1: number\n y1: number\n x2: number\n y2: number\n labelX: number\n labelY: number\n}\n\nconst RESPONSE_CURVES: Option<Curve>[] = [\n {\n value: RESPONSE_CURVE_7,\n label: 'Always maxed out.',\n },\n {\n value: RESPONSE_CURVE_6,\n label: 'Most sensitive.',\n },\n {\n value: RESPONSE_CURVE_5,\n label: 'Moderately sensitive.',\n },\n {\n value: RESPONSE_CURVE_4,\n label: 'A little sensitive.',\n },\n {\n value: RESPONSE_CURVE_0,\n label: 'Linear, no change.',\n },\n {\n value: RESPONSE_CURVE_1,\n label: 'A little less sensitive.',\n },\n {\n value: RESPONSE_CURVE_2,\n label: 'Even less sensitive.',\n },\n {\n value: RESPONSE_CURVE_3,\n label: 'Least sensitive.',\n },\n]\n\n// const width = 218\n// const height = 150\nconst axisOffset = 20\nconst buttonSize = 15\n\nconst axisX1 = axisOffset\nconst axisY1 = axisOffset\n\ntype ResponseCurveProps = {\n autosize: boolean\n disabled?: boolean\n inverted: boolean\n onChange: (event: { target: { value: Curve } }) => void\n Tooltip: React.FC<TooltipProps>\n value: Curve\n}\n\nconst ResponseCurve = (props: ResponseCurveProps) => {\n const {\n Tooltip = DefaultTooltip,\n autosize,\n disabled,\n inverted,\n onChange,\n value: responseCurve,\n } = props\n\n const ref = useRef(null)\n const svgRef = useRef(null)\n const { height: ourHeight, width: ourWidth } = useComponentSize(ref)\n\n const width = autosize ? ourWidth || 218 : 218\n const height = autosize ? ourHeight || 150 : 150\n\n const axisX2 = width - axisOffset\n const axisY2 = height - axisOffset\n\n const xMid = width / 2\n const yMid = height / 2\n\n const svgProps = { ref: svgRef }\n\n const responseCurves = RESPONSE_CURVES.map(\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: <explanation>\n ({ value, label }): ResponseCurve => {\n let c1 = 0\n let c2 = 0\n let x1 = axisX1\n let y1 = inverted ? axisY1 : axisY2\n let x2 = axisX2\n let y2 = inverted ? axisY2 : axisY1\n let labelX = xMid\n let labelY = yMid\n switch (value) {\n case RESPONSE_CURVE_0:\n c1 = xMid\n c2 = yMid\n labelY += 3\n\n break\n case RESPONSE_CURVE_1:\n c1 = inverted ? xMid + width * 0.13 : xMid - width * 0.13\n c2 = yMid - height * 0.13\n labelX = inverted ? xMid + width * 0.1 : xMid - width * 0.1\n labelY = yMid - height * 0.09\n break\n\n case RESPONSE_CURVE_2:\n c1 = inverted ? xMid + width * 0.25 : xMid - width * 0.25\n c2 = yMid - height * 0.25\n labelX = inverted ? xMid + width * 0.2 : xMid - width * 0.2\n labelY = yMid - height * 0.17\n break\n\n case RESPONSE_CURVE_3:\n c1 = inverted ? xMid + width * 0.35 : xMid - width * 0.35\n c2 = yMid - height * 0.35\n labelX = inverted ? xMid + width * 0.28 : xMid - width * 0.28\n labelY = yMid - height * 0.25\n break\n\n case RESPONSE_CURVE_4:\n c1 = inverted ? xMid - width * 0.13 : xMid + width * 0.13\n c2 = yMid + height * 0.13\n labelX = inverted ? xMid - width * 0.1 : xMid + width * 0.1\n labelY = yMid + height * 0.1\n break\n\n case RESPONSE_CURVE_5:\n c1 = inverted ? xMid - width * 0.25 : xMid + width * 0.25\n c2 = yMid + height * 0.25\n labelX = inverted ? xMid - width * 0.2 : xMid + width * 0.2\n labelY = yMid + height * 0.18\n break\n\n case RESPONSE_CURVE_6:\n c1 = inverted ? xMid - width * 0.35 : xMid + width * 0.35\n c2 = yMid + height * 0.35\n labelX = inverted ? xMid - width * 0.28 : xMid + width * 0.28\n labelY = yMid + height * 0.25\n break\n\n case RESPONSE_CURVE_7:\n x1 = inverted ? axisX1 : axisX2\n y1 = axisY1\n x2 = x1\n y2 = axisY2\n c1 = x1\n c2 = yMid\n labelX = x1 - 5\n labelY = height - 30\n break\n\n default:\n break\n }\n return {\n value,\n label,\n c1,\n c2,\n x1,\n y1,\n x2,\n y2,\n labelX,\n labelY,\n }\n },\n )\n\n return (\n <div\n className=\"response-curve-picker\"\n ref={ref}>\n <svg {...svgProps}>\n <rect\n className=\"container\"\n height={height}\n rx={3}\n ry={3}\n width={width}\n x={0}\n y={0}\n />\n\n <SVGText\n className=\"axis\"\n textAnchor=\"middle\"\n transform={`translate(${axisX1 - 14} ${height / 2}) rotate(90)`}\n x={0}\n y={0}\n text=\"Applied force\"\n />\n\n <SVGText\n className=\"axis\"\n textAnchor=\"middle\"\n transform={`translate(${width / 2} ${axisY2 + 13})`}\n x={0}\n y={0}\n text=\"Output (velocity)\"\n />\n\n <line\n className=\"axis\"\n x1={axisX1}\n x2={axisX1}\n y1={axisY1}\n y2={axisY2}\n />\n <line\n className=\"axis\"\n x1={axisX1}\n x2={axisX2}\n y1={axisY2}\n y2={axisY2}\n />\n\n {responseCurves.map(\n ({ value, label, x1, y1, x2, y2, c1, c2, labelX, labelY }) => (\n <g key={value}>\n <path\n className={value === responseCurve ? 'curve-selected' : 'curve'}\n d={`M${x1} ${y1} C ${c1} ${c2}, ${c1} ${c2}, ${x2} ${y2}`}\n />\n\n <Tooltip\n placement=\"left\"\n title={label}>\n <rect\n className={\n value === responseCurve ? 'button-selected' : 'button'\n }\n height={buttonSize}\n onClick={\n disabled\n ? f => f\n : () =>\n onChange({\n target: {\n value: Number.parseInt(String(value)) as Curve,\n },\n })\n }\n transform={`translate(${labelX + 3} ${labelY - buttonSize / 1.05}) rotate(45)`}\n width={buttonSize}\n />\n </Tooltip>\n\n <text\n className={\n value === responseCurve ? 'button-selected' : 'button'\n }\n transform={`translate(${labelX} ${labelY})`}>\n {value}\n <title>{label}</title>\n </text>\n </g>\n ),\n )}\n </svg>\n </div>\n )\n}\n\nexport default ResponseCurve\n\nexport { RESPONSE_CURVES }\n\nexport type { Curve, ResponseCurve, ResponseCurveProps }\n"],"names":["Statuses","MASK_CHANNEL","MASK_STATUS","statusOptions","getStatusLabel","val","_a","value","combineStatusWithChannel","channel","status","extractStatusAndChannel","MEASUREMENT_ELEMENT_ID","RESPONSE_CURVE_0","RESPONSE_CURVE_1","RESPONSE_CURVE_2","RESPONSE_CURVE_3","RESPONSE_CURVE_4","RESPONSE_CURVE_5","RESPONSE_CURVE_6","RESPONSE_CURVE_7","RESPONSE_CURVES"],"mappings":";;AAEA,MAAMA,IAAW;AAAA,EACf,SAAS;AAAA;AAAA,EACT,QAAQ;AAAA;AAAA,EACR,YAAY;AAAA;AAAA,EACZ,eAAe;AAAA;AAAA,EACf,eAAe;AAAA;AAAA,EACf,iBAAiB;AAAA;AAAA,EACjB,YAAY;AAAA;AACd,GAIMC,IAAe,IACfC,IAAc,KAEdC,IAAkC;AAAA,EACtC,EAAE,OAAOH,EAAS,QAAQ,OAAO,UAAU;AAAA,EAC3C,EAAE,OAAOA,EAAS,SAAS,OAAO,aAAa;AAAA,EAC/C,EAAE,OAAOA,EAAS,eAAe,OAAO,iBAAiB;AAAA,EACzD,EAAE,OAAOA,EAAS,eAAe,OAAO,iBAAiB;AAAA,EACzD,EAAE,OAAOA,EAAS,YAAY,OAAO,aAAa;AAAA,EAClD,EAAE,OAAOA,EAAS,iBAAiB,OAAO,mBAAmB;AAAA,EAC7D,EAAE,OAAOA,EAAS,YAAY,OAAO,cAAc;AACrD,GAEMI,IAAiB,CAACC;;AACtB,WAAAC,IAAAH,EAAc,OAAO,CAAC,EAAE,OAAAI,EAAM,MAAMA,MAAUF,CAAG,EAAE,CAAC,MAApD,gBAAAC,EAAuD,UAAS;AAAA,GAE5DE,IAA2B,CAACC,GAAiBC,MACjDD,IAAWC,KAAU,GAEjBC,IAA0B,CAC9BD,OAII;AAAA,EACJ,SAAWA,IAASR,MAAgB,IAAK;AAAA,EACzC,SAASQ,IAAST;AACpB,ICvCMW,IAAyB,mCCIzBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GAyBnBC,IAAmC;AAAA,EACvC;AAAA,IACE,OAAOD;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOD;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOD;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOD;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOJ;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOC;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOC;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOC;AAAA,IACP,OAAO;AAAA,EAAA;AAEX;"}
1
+ {"version":3,"file":"index.es.js","sources":["../lib/midi/export.ts","../lib/other/SVGText.tsx"],"sourcesContent":["import type { Option } from 'lib/pickers/Select'\n\nconst Statuses = {\n noteOff: 8, // 1000\n noteOn: 9, // 1001\n aftertouch: 10, // 1010\n controlChange: 11, // 1011\n programChange: 12, // 1100\n channelPressure: 13, // 1101\n pitchWheel: 14, // 1110\n} as const\n\ntype Status = (typeof Statuses)[keyof typeof Statuses]\n\nconst MASK_CHANNEL = 15 // 00001111\nconst MASK_STATUS = 240 // 01110000\n\nconst statusOptions: Option<Status>[] = [\n { value: Statuses.noteOn, label: 'Note On' },\n { value: Statuses.noteOff, label: 'Note Stack' },\n { value: Statuses.controlChange, label: 'Control Change' },\n { value: Statuses.programChange, label: 'Program Change' },\n { value: Statuses.aftertouch, label: 'Aftertouch' },\n { value: Statuses.channelPressure, label: 'Channel Pressure' },\n { value: Statuses.pitchWheel, label: 'Pitch Wheel' },\n]\n\nconst getStatusLabel = (val: Status) =>\n statusOptions.filter(({ value }) => value === val)[0]?.label || '???'\n\nconst combineStatusWithChannel = (channel: number, status: Status) =>\n channel | (status << 4)\n\nconst extractStatusAndChannel = (\n status: number,\n): {\n status: Status\n channel: number\n} => ({\n status: (((status & MASK_STATUS) >> 4) | 8) as Status,\n channel: status & MASK_CHANNEL,\n})\n\nconst RESPONSE_CURVE_0 = 0\nconst RESPONSE_CURVE_1 = 1\nconst RESPONSE_CURVE_2 = 2\nconst RESPONSE_CURVE_3 = 3\nconst RESPONSE_CURVE_4 = 4\nconst RESPONSE_CURVE_5 = 5\nconst RESPONSE_CURVE_6 = 6\nconst RESPONSE_CURVE_7 = 7\n\ntype Curve =\n | typeof RESPONSE_CURVE_0\n | typeof RESPONSE_CURVE_1\n | typeof RESPONSE_CURVE_2\n | typeof RESPONSE_CURVE_3\n | typeof RESPONSE_CURVE_4\n | typeof RESPONSE_CURVE_5\n | typeof RESPONSE_CURVE_6\n | typeof RESPONSE_CURVE_7\n\nconst responseCurves: Option<Curve>[] = [\n {\n value: RESPONSE_CURVE_7,\n label: 'Always maxed out.',\n },\n {\n value: RESPONSE_CURVE_6,\n label: 'Most sensitive.',\n },\n {\n value: RESPONSE_CURVE_5,\n label: 'Moderately sensitive.',\n },\n {\n value: RESPONSE_CURVE_4,\n label: 'A little sensitive.',\n },\n {\n value: RESPONSE_CURVE_0,\n label: 'Linear, no change.',\n },\n {\n value: RESPONSE_CURVE_1,\n label: 'A little less sensitive.',\n },\n {\n value: RESPONSE_CURVE_2,\n label: 'Even less sensitive.',\n },\n {\n value: RESPONSE_CURVE_3,\n label: 'Least sensitive.',\n },\n]\n\nexport {\n combineStatusWithChannel,\n extractStatusAndChannel,\n getStatusLabel,\n MASK_CHANNEL,\n MASK_STATUS,\n responseCurves,\n Statuses,\n statusOptions,\n}\n\nexport type { Curve, Status }\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nconst MEASUREMENT_ELEMENT_ID = '__react_svg_text_measurement_id'\n\ntype WordsByLine = {\n words: string[]\n width: number\n showLine: boolean\n}\n\nconst calculateWordsByLines = (\n text: string,\n wordWidths: WordWidths,\n maxWidth: number,\n maxHeight: number,\n) => {\n const { lineHeight, spaceWidth, wordsWithComputedWidth } = wordWidths\n\n return text.split(/\\s+/).reduce((result: WordsByLine[], word) => {\n const wordWidth = wordsWithComputedWidth[word]\n const currentLine = result[result.length - 1]\n if (currentLine && currentLine.width + wordWidth + spaceWidth < maxWidth) {\n // Word can be added to an existing line\n currentLine.words.push(word)\n currentLine.width += wordWidth + spaceWidth\n } else {\n // Add first word to line or word is too long to scaleToFit on existing line\n const newLine: WordsByLine = {\n words: [word],\n width: wordWidth,\n showLine: maxHeight\n ? lineHeight * (result.length + 1) < maxHeight\n : true,\n }\n result.push(newLine)\n }\n return result\n }, [])\n}\n\ntype WordWidths = {\n wordsWithComputedWidth: Record<string, number>\n spaceWidth: number\n lineHeight: number\n}\n\nconst calculateWordWidths = (\n style?: CSSStyleDeclaration,\n textNode?: SVGGraphicsElement | null,\n text?: string,\n): WordWidths | undefined => {\n if (style && textNode) {\n // biome-ignore lint/complexity/noForEach: <explanation>\n Array.from(style).forEach(key =>\n textNode.style.setProperty(\n key,\n style.getPropertyValue(key),\n style.getPropertyPriority(key),\n ),\n )\n const wordArray = [...new Set(String(text).split(/\\s+/))]\n const wordsWithComputedWidth = wordArray.reduce((wordMap, word) => {\n textNode.textContent = word\n // biome-ignore lint/performance/noAccumulatingSpread: <explanation>\n return { ...wordMap, [word]: textNode.getBBox().width }\n }, {})\n\n textNode.textContent = '\\u00A0'\n\n const spaceWidth =\n (textNode as SVGTextContentElement)?.getComputedTextLength?.() || 8\n const lineHeight = textNode.getBBox().height\n\n textNode.setAttribute('style', '')\n return { wordsWithComputedWidth, spaceWidth, lineHeight }\n }\n return undefined\n}\n\ntype TextProps = Partial<HTMLOrSVGElement> & {\n className?: string\n dx?: number\n dy?: number\n maxHeight?: number\n maxWidth?: number\n transform?: string\n text: string\n textAnchor?: React.CSSProperties['textAnchor']\n verticalAnchor?: 'start' | 'middle' | 'end'\n x?: number\n y?: number\n}\n\nconst Text = (props: TextProps) => {\n const {\n className = '',\n dx = 0,\n dy = 0,\n maxHeight = 1000,\n maxWidth = 1000,\n // textAnchor = 'start',\n text = '',\n verticalAnchor = 'start',\n x = 0,\n y = 0,\n transform = '',\n ...rest\n } = props\n const [wordWidths, setWordWidths] = useState<WordWidths>()\n const [textLines, setTextLines] = useState<WordsByLine[]>([])\n const [style, setComputedStyle] = useState<CSSStyleDeclaration>()\n const measureRef = useRef<SVGSVGElement | HTMLElement>({} as HTMLElement)\n\n const displayedLines: WordsByLine[] = useMemo(() => {\n const result = textLines.filter(({ showLine }) => showLine)\n return result.length\n ? result\n : text\n .split(/\\n/)\n .map(line => ({ words: [line], width: 0, showLine: true }))\n }, [textLines, text])\n\n const ref: React.LegacyRef<SVGTextElement> = useCallback(\n (node: SVGTextElement | null) => {\n setComputedStyle(\n node !== null ? window.getComputedStyle(node) : undefined,\n )\n },\n [],\n )\n\n useEffect(() => {\n const el = document.getElementById(MEASUREMENT_ELEMENT_ID)\n if (el === null) {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n svg.setAttribute('id', MEASUREMENT_ELEMENT_ID)\n document.body.appendChild(svg)\n svg.appendChild(\n document.createElementNS('http://www.w3.org/2000/svg', 'text'),\n )\n measureRef.current = svg\n return () => {\n document.body.removeChild(svg)\n }\n }\n measureRef.current = el\n }, [])\n\n useEffect(() => {\n const wordWithWidths = calculateWordWidths(\n style,\n measureRef.current as SVGGraphicsElement | null,\n text,\n )\n\n setWordWidths(wordWithWidths)\n }, [text, style])\n\n useEffect(() => {\n if (maxWidth && wordWidths) {\n const lines = text\n .split(/\\n/)\n .flatMap(line =>\n calculateWordsByLines(line, wordWidths, maxWidth, maxHeight),\n )\n\n setTextLines(lines)\n }\n }, [maxHeight, maxWidth, wordWidths, text])\n\n const startDy = useMemo(() => {\n if (wordWidths?.lineHeight) {\n switch (verticalAnchor) {\n case 'start':\n return wordWidths.lineHeight\n\n case 'middle':\n return -(((displayedLines.length - 1) * wordWidths.lineHeight) / 2)\n\n default:\n return -(displayedLines.length - 1) * wordWidths.lineHeight\n }\n }\n return 0\n }, [displayedLines.length, verticalAnchor, wordWidths?.lineHeight])\n\n return (\n <text\n className={className}\n ref={ref}\n dx={dx}\n dy={dy}\n x={x}\n y={y}\n // textAnchor={textAnchor}\n transform={transform}\n {...rest}>\n <>\n {displayedLines.map((line, idx) => (\n <tspan\n dx={x + dx}\n dy={idx === 0 ? startDy + dy : wordWidths?.lineHeight || 0}\n key={idx}\n x={0}>\n {line.words.join(' ')}\n </tspan>\n ))}\n {textLines.length && displayedLines.length !== textLines.length && (\n <>\n <tspan>...</tspan>\n <title>{text}</title>\n </>\n )}\n </>\n </text>\n )\n}\n\nexport default Text\n\nexport { MEASUREMENT_ELEMENT_ID }\n\nexport type { TextProps, WordWidths, WordsByLine }\n"],"names":["Statuses","MASK_CHANNEL","MASK_STATUS","statusOptions","getStatusLabel","val","_a","value","combineStatusWithChannel","channel","status","extractStatusAndChannel","RESPONSE_CURVE_0","RESPONSE_CURVE_1","RESPONSE_CURVE_2","RESPONSE_CURVE_3","RESPONSE_CURVE_4","RESPONSE_CURVE_5","RESPONSE_CURVE_6","RESPONSE_CURVE_7","responseCurves","MEASUREMENT_ELEMENT_ID"],"mappings":";;AAEA,MAAMA,IAAW;AAAA,EACf,SAAS;AAAA;AAAA,EACT,QAAQ;AAAA;AAAA,EACR,YAAY;AAAA;AAAA,EACZ,eAAe;AAAA;AAAA,EACf,eAAe;AAAA;AAAA,EACf,iBAAiB;AAAA;AAAA,EACjB,YAAY;AAAA;AACd,GAIMC,IAAe,IACfC,IAAc,KAEdC,IAAkC;AAAA,EACtC,EAAE,OAAOH,EAAS,QAAQ,OAAO,UAAU;AAAA,EAC3C,EAAE,OAAOA,EAAS,SAAS,OAAO,aAAa;AAAA,EAC/C,EAAE,OAAOA,EAAS,eAAe,OAAO,iBAAiB;AAAA,EACzD,EAAE,OAAOA,EAAS,eAAe,OAAO,iBAAiB;AAAA,EACzD,EAAE,OAAOA,EAAS,YAAY,OAAO,aAAa;AAAA,EAClD,EAAE,OAAOA,EAAS,iBAAiB,OAAO,mBAAmB;AAAA,EAC7D,EAAE,OAAOA,EAAS,YAAY,OAAO,cAAc;AACrD,GAEMI,IAAiB,CAACC;;AACtB,WAAAC,IAAAH,EAAc,OAAO,CAAC,EAAE,OAAAI,EAAM,MAAMA,MAAUF,CAAG,EAAE,CAAC,MAApD,gBAAAC,EAAuD,UAAS;AAAA,GAE5DE,IAA2B,CAACC,GAAiBC,MACjDD,IAAWC,KAAU,GAEjBC,IAA0B,CAC9BD,OAII;AAAA,EACJ,SAAWA,IAASR,MAAgB,IAAK;AAAA,EACzC,SAASQ,IAAST;AACpB,IAEMW,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GACnBC,IAAmB,GAYnBC,IAAkC;AAAA,EACtC;AAAA,IACE,OAAOD;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOD;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOD;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOD;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOJ;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOC;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOC;AAAA,IACP,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,OAAOC;AAAA,IACP,OAAO;AAAA,EAAA;AAEX,GC7FMM,IAAyB;"}
@@ -24,4 +24,46 @@ const extractStatusAndChannel = (status) => ({
24
24
  status: (((status & MASK_STATUS) >> 4) | 8),
25
25
  channel: status & MASK_CHANNEL,
26
26
  });
27
- export { combineStatusWithChannel, extractStatusAndChannel, getStatusLabel, MASK_CHANNEL, MASK_STATUS, statusOptions, Statuses, };
27
+ const RESPONSE_CURVE_0 = 0;
28
+ const RESPONSE_CURVE_1 = 1;
29
+ const RESPONSE_CURVE_2 = 2;
30
+ const RESPONSE_CURVE_3 = 3;
31
+ const RESPONSE_CURVE_4 = 4;
32
+ const RESPONSE_CURVE_5 = 5;
33
+ const RESPONSE_CURVE_6 = 6;
34
+ const RESPONSE_CURVE_7 = 7;
35
+ const responseCurves = [
36
+ {
37
+ value: RESPONSE_CURVE_7,
38
+ label: 'Always maxed out.',
39
+ },
40
+ {
41
+ value: RESPONSE_CURVE_6,
42
+ label: 'Most sensitive.',
43
+ },
44
+ {
45
+ value: RESPONSE_CURVE_5,
46
+ label: 'Moderately sensitive.',
47
+ },
48
+ {
49
+ value: RESPONSE_CURVE_4,
50
+ label: 'A little sensitive.',
51
+ },
52
+ {
53
+ value: RESPONSE_CURVE_0,
54
+ label: 'Linear, no change.',
55
+ },
56
+ {
57
+ value: RESPONSE_CURVE_1,
58
+ label: 'A little less sensitive.',
59
+ },
60
+ {
61
+ value: RESPONSE_CURVE_2,
62
+ label: 'Even less sensitive.',
63
+ },
64
+ {
65
+ value: RESPONSE_CURVE_3,
66
+ label: 'Least sensitive.',
67
+ },
68
+ ];
69
+ export { combineStatusWithChannel, extractStatusAndChannel, getStatusLabel, MASK_CHANNEL, MASK_STATUS, responseCurves, Statuses, statusOptions, };
@@ -1,50 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useRef } from 'react';
3
3
  import useComponentSize from '../hooks/useComponentSize';
4
+ import { responseCurves as origResponseCurves, } from '../midi/export';
4
5
  import DefaultTooltip from '../other/DefaultTooltip';
5
6
  import SVGText from '../other/SVGText';
6
- const RESPONSE_CURVE_0 = 0;
7
- const RESPONSE_CURVE_1 = 1;
8
- const RESPONSE_CURVE_2 = 2;
9
- const RESPONSE_CURVE_3 = 3;
10
- const RESPONSE_CURVE_4 = 4;
11
- const RESPONSE_CURVE_5 = 5;
12
- const RESPONSE_CURVE_6 = 6;
13
- const RESPONSE_CURVE_7 = 7;
14
- const RESPONSE_CURVES = [
15
- {
16
- value: RESPONSE_CURVE_7,
17
- label: 'Always maxed out.',
18
- },
19
- {
20
- value: RESPONSE_CURVE_6,
21
- label: 'Most sensitive.',
22
- },
23
- {
24
- value: RESPONSE_CURVE_5,
25
- label: 'Moderately sensitive.',
26
- },
27
- {
28
- value: RESPONSE_CURVE_4,
29
- label: 'A little sensitive.',
30
- },
31
- {
32
- value: RESPONSE_CURVE_0,
33
- label: 'Linear, no change.',
34
- },
35
- {
36
- value: RESPONSE_CURVE_1,
37
- label: 'A little less sensitive.',
38
- },
39
- {
40
- value: RESPONSE_CURVE_2,
41
- label: 'Even less sensitive.',
42
- },
43
- {
44
- value: RESPONSE_CURVE_3,
45
- label: 'Least sensitive.',
46
- },
47
- ];
48
7
  // const width = 218
49
8
  // const height = 150
50
9
  const axisOffset = 20;
@@ -63,7 +22,7 @@ const ResponseCurve = (props) => {
63
22
  const xMid = width / 2;
64
23
  const yMid = height / 2;
65
24
  const svgProps = { ref: svgRef };
66
- const responseCurves = RESPONSE_CURVES.map(
25
+ const responseCurves = origResponseCurves.map(
67
26
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: <explanation>
68
27
  ({ value, label }) => {
69
28
  let c1 = 0;
@@ -75,48 +34,48 @@ const ResponseCurve = (props) => {
75
34
  let labelX = xMid;
76
35
  let labelY = yMid;
77
36
  switch (value) {
78
- case RESPONSE_CURVE_0:
37
+ case responseCurves[0].value:
79
38
  c1 = xMid;
80
39
  c2 = yMid;
81
40
  labelY += 3;
82
41
  break;
83
- case RESPONSE_CURVE_1:
42
+ case responseCurves[1].value:
84
43
  c1 = inverted ? xMid + width * 0.13 : xMid - width * 0.13;
85
44
  c2 = yMid - height * 0.13;
86
45
  labelX = inverted ? xMid + width * 0.1 : xMid - width * 0.1;
87
46
  labelY = yMid - height * 0.09;
88
47
  break;
89
- case RESPONSE_CURVE_2:
48
+ case responseCurves[2].value:
90
49
  c1 = inverted ? xMid + width * 0.25 : xMid - width * 0.25;
91
50
  c2 = yMid - height * 0.25;
92
51
  labelX = inverted ? xMid + width * 0.2 : xMid - width * 0.2;
93
52
  labelY = yMid - height * 0.17;
94
53
  break;
95
- case RESPONSE_CURVE_3:
54
+ case responseCurves[3].value:
96
55
  c1 = inverted ? xMid + width * 0.35 : xMid - width * 0.35;
97
56
  c2 = yMid - height * 0.35;
98
57
  labelX = inverted ? xMid + width * 0.28 : xMid - width * 0.28;
99
58
  labelY = yMid - height * 0.25;
100
59
  break;
101
- case RESPONSE_CURVE_4:
60
+ case responseCurves[4].value:
102
61
  c1 = inverted ? xMid - width * 0.13 : xMid + width * 0.13;
103
62
  c2 = yMid + height * 0.13;
104
63
  labelX = inverted ? xMid - width * 0.1 : xMid + width * 0.1;
105
64
  labelY = yMid + height * 0.1;
106
65
  break;
107
- case RESPONSE_CURVE_5:
66
+ case responseCurves[5].value:
108
67
  c1 = inverted ? xMid - width * 0.25 : xMid + width * 0.25;
109
68
  c2 = yMid + height * 0.25;
110
69
  labelX = inverted ? xMid - width * 0.2 : xMid + width * 0.2;
111
70
  labelY = yMid + height * 0.18;
112
71
  break;
113
- case RESPONSE_CURVE_6:
72
+ case responseCurves[6].value:
114
73
  c1 = inverted ? xMid - width * 0.35 : xMid + width * 0.35;
115
74
  c2 = yMid + height * 0.35;
116
75
  labelX = inverted ? xMid - width * 0.28 : xMid + width * 0.28;
117
76
  labelY = yMid + height * 0.25;
118
77
  break;
119
- case RESPONSE_CURVE_7:
78
+ case responseCurves[7].value:
120
79
  x1 = inverted ? axisX1 : axisX2;
121
80
  y1 = axisY1;
122
81
  x2 = x1;
@@ -151,4 +110,3 @@ const ResponseCurve = (props) => {
151
110
  }), transform: `translate(${labelX + 3} ${labelY - buttonSize / 1.05}) rotate(45)`, width: buttonSize }) }), _jsxs("text", { className: value === responseCurve ? 'button-selected' : 'button', transform: `translate(${labelX} ${labelY})`, children: [value, _jsx("title", { children: label })] })] }, value)))] }) }));
152
111
  };
153
112
  export default ResponseCurve;
154
- export { RESPONSE_CURVES };
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, useCallback } from 'react';
3
+ import { responseCurves } from '../midi/export';
3
4
  import DefaultTooltip from '../other/DefaultTooltip';
4
5
  import { findObj } from '../utils';
5
- import ResponseCurve, { RESPONSE_CURVES } from './ResponseCurve';
6
+ import ResponseCurve from './ResponseCurve';
6
7
  import Select from './Select';
7
8
  const ResponseCurvePicker = forwardRef((props, ref) => {
8
9
  const { Tooltip = DefaultTooltip, inverted = false, onChange, value, ...rest } = props;
9
- const Placeholder = useCallback(() => (_jsx("div", { className: "singleValue", children: findObj('value', value)(RESPONSE_CURVES)?.label })), [value]);
10
+ const Placeholder = useCallback(() => (_jsx("div", { className: "singleValue", children: findObj('value', value)(responseCurves)?.label })), [value]);
10
11
  const MenuList = useCallback(({ setValue }) => (_jsx(ResponseCurve, { autosize: true, inverted: inverted, onChange: ({ target: { value: v } }) => {
11
12
  setValue(v);
12
13
  onChange(v);
@@ -18,4 +18,15 @@ declare const extractStatusAndChannel: (status: number) => {
18
18
  status: Status;
19
19
  channel: number;
20
20
  };
21
- export { combineStatusWithChannel, extractStatusAndChannel, getStatusLabel, MASK_CHANNEL, MASK_STATUS, statusOptions, Statuses, type Status, };
21
+ declare const RESPONSE_CURVE_0 = 0;
22
+ declare const RESPONSE_CURVE_1 = 1;
23
+ declare const RESPONSE_CURVE_2 = 2;
24
+ declare const RESPONSE_CURVE_3 = 3;
25
+ declare const RESPONSE_CURVE_4 = 4;
26
+ declare const RESPONSE_CURVE_5 = 5;
27
+ declare const RESPONSE_CURVE_6 = 6;
28
+ declare const RESPONSE_CURVE_7 = 7;
29
+ type Curve = typeof RESPONSE_CURVE_0 | typeof RESPONSE_CURVE_1 | typeof RESPONSE_CURVE_2 | typeof RESPONSE_CURVE_3 | typeof RESPONSE_CURVE_4 | typeof RESPONSE_CURVE_5 | typeof RESPONSE_CURVE_6 | typeof RESPONSE_CURVE_7;
30
+ declare const responseCurves: Option<Curve>[];
31
+ export { combineStatusWithChannel, extractStatusAndChannel, getStatusLabel, MASK_CHANNEL, MASK_STATUS, responseCurves, Statuses, statusOptions, };
32
+ export type { Curve, Status };
@@ -1,14 +1,5 @@
1
+ import { type Curve } from '../midi/export';
1
2
  import { type TooltipProps } from '../other/DefaultTooltip';
2
- import type { Option } from './Select';
3
- declare const RESPONSE_CURVE_0 = 0;
4
- declare const RESPONSE_CURVE_1 = 1;
5
- declare const RESPONSE_CURVE_2 = 2;
6
- declare const RESPONSE_CURVE_3 = 3;
7
- declare const RESPONSE_CURVE_4 = 4;
8
- declare const RESPONSE_CURVE_5 = 5;
9
- declare const RESPONSE_CURVE_6 = 6;
10
- declare const RESPONSE_CURVE_7 = 7;
11
- type Curve = typeof RESPONSE_CURVE_0 | typeof RESPONSE_CURVE_1 | typeof RESPONSE_CURVE_2 | typeof RESPONSE_CURVE_3 | typeof RESPONSE_CURVE_4 | typeof RESPONSE_CURVE_5 | typeof RESPONSE_CURVE_6 | typeof RESPONSE_CURVE_7;
12
3
  type ResponseCurve = {
13
4
  value: Curve;
14
5
  label: React.ReactNode;
@@ -21,7 +12,6 @@ type ResponseCurve = {
21
12
  labelX: number;
22
13
  labelY: number;
23
14
  };
24
- declare const RESPONSE_CURVES: Option<Curve>[];
25
15
  type ResponseCurveProps = {
26
16
  autosize: boolean;
27
17
  disabled?: boolean;
@@ -36,5 +26,4 @@ type ResponseCurveProps = {
36
26
  };
37
27
  declare const ResponseCurve: (props: ResponseCurveProps) => import("react/jsx-runtime").JSX.Element;
38
28
  export default ResponseCurve;
39
- export { RESPONSE_CURVES };
40
- export type { Curve, ResponseCurve, ResponseCurveProps };
29
+ export type { ResponseCurve, ResponseCurveProps };
@@ -1,6 +1,6 @@
1
1
  import type { GroupBase, SelectInstance } from 'react-select';
2
+ import { type Curve } from '../midi/export';
2
3
  import { type TooltipProps } from '../other/DefaultTooltip';
3
- import { type Curve } from './ResponseCurve';
4
4
  import type { Option, SelectProps } from './Select';
5
5
  type ResponseCurvePickerProps = SelectProps<Curve> & {
6
6
  inverted?: boolean;
@@ -41,13 +41,69 @@ const extractStatusAndChannel = (
41
41
  channel: status & MASK_CHANNEL,
42
42
  })
43
43
 
44
+ const RESPONSE_CURVE_0 = 0
45
+ const RESPONSE_CURVE_1 = 1
46
+ const RESPONSE_CURVE_2 = 2
47
+ const RESPONSE_CURVE_3 = 3
48
+ const RESPONSE_CURVE_4 = 4
49
+ const RESPONSE_CURVE_5 = 5
50
+ const RESPONSE_CURVE_6 = 6
51
+ const RESPONSE_CURVE_7 = 7
52
+
53
+ type Curve =
54
+ | typeof RESPONSE_CURVE_0
55
+ | typeof RESPONSE_CURVE_1
56
+ | typeof RESPONSE_CURVE_2
57
+ | typeof RESPONSE_CURVE_3
58
+ | typeof RESPONSE_CURVE_4
59
+ | typeof RESPONSE_CURVE_5
60
+ | typeof RESPONSE_CURVE_6
61
+ | typeof RESPONSE_CURVE_7
62
+
63
+ const responseCurves: Option<Curve>[] = [
64
+ {
65
+ value: RESPONSE_CURVE_7,
66
+ label: 'Always maxed out.',
67
+ },
68
+ {
69
+ value: RESPONSE_CURVE_6,
70
+ label: 'Most sensitive.',
71
+ },
72
+ {
73
+ value: RESPONSE_CURVE_5,
74
+ label: 'Moderately sensitive.',
75
+ },
76
+ {
77
+ value: RESPONSE_CURVE_4,
78
+ label: 'A little sensitive.',
79
+ },
80
+ {
81
+ value: RESPONSE_CURVE_0,
82
+ label: 'Linear, no change.',
83
+ },
84
+ {
85
+ value: RESPONSE_CURVE_1,
86
+ label: 'A little less sensitive.',
87
+ },
88
+ {
89
+ value: RESPONSE_CURVE_2,
90
+ label: 'Even less sensitive.',
91
+ },
92
+ {
93
+ value: RESPONSE_CURVE_3,
94
+ label: 'Least sensitive.',
95
+ },
96
+ ]
97
+
44
98
  export {
45
99
  combineStatusWithChannel,
46
100
  extractStatusAndChannel,
47
101
  getStatusLabel,
48
102
  MASK_CHANNEL,
49
103
  MASK_STATUS,
50
- statusOptions,
104
+ responseCurves,
51
105
  Statuses,
52
- type Status,
106
+ statusOptions,
53
107
  }
108
+
109
+ export type { Curve, Status }
@@ -1,27 +1,11 @@
1
1
  import { useRef } from 'react'
2
2
  import useComponentSize from '../hooks/useComponentSize'
3
+ import {
4
+ type Curve,
5
+ responseCurves as origResponseCurves,
6
+ } from '../midi/export'
3
7
  import DefaultTooltip, { type TooltipProps } from '../other/DefaultTooltip'
4
8
  import SVGText from '../other/SVGText'
5
- import type { Option } from './Select'
6
-
7
- const RESPONSE_CURVE_0 = 0
8
- const RESPONSE_CURVE_1 = 1
9
- const RESPONSE_CURVE_2 = 2
10
- const RESPONSE_CURVE_3 = 3
11
- const RESPONSE_CURVE_4 = 4
12
- const RESPONSE_CURVE_5 = 5
13
- const RESPONSE_CURVE_6 = 6
14
- const RESPONSE_CURVE_7 = 7
15
-
16
- type Curve =
17
- | typeof RESPONSE_CURVE_0
18
- | typeof RESPONSE_CURVE_1
19
- | typeof RESPONSE_CURVE_2
20
- | typeof RESPONSE_CURVE_3
21
- | typeof RESPONSE_CURVE_4
22
- | typeof RESPONSE_CURVE_5
23
- | typeof RESPONSE_CURVE_6
24
- | typeof RESPONSE_CURVE_7
25
9
 
26
10
  type ResponseCurve = {
27
11
  value: Curve
@@ -36,41 +20,6 @@ type ResponseCurve = {
36
20
  labelY: number
37
21
  }
38
22
 
39
- const RESPONSE_CURVES: Option<Curve>[] = [
40
- {
41
- value: RESPONSE_CURVE_7,
42
- label: 'Always maxed out.',
43
- },
44
- {
45
- value: RESPONSE_CURVE_6,
46
- label: 'Most sensitive.',
47
- },
48
- {
49
- value: RESPONSE_CURVE_5,
50
- label: 'Moderately sensitive.',
51
- },
52
- {
53
- value: RESPONSE_CURVE_4,
54
- label: 'A little sensitive.',
55
- },
56
- {
57
- value: RESPONSE_CURVE_0,
58
- label: 'Linear, no change.',
59
- },
60
- {
61
- value: RESPONSE_CURVE_1,
62
- label: 'A little less sensitive.',
63
- },
64
- {
65
- value: RESPONSE_CURVE_2,
66
- label: 'Even less sensitive.',
67
- },
68
- {
69
- value: RESPONSE_CURVE_3,
70
- label: 'Least sensitive.',
71
- },
72
- ]
73
-
74
23
  // const width = 218
75
24
  // const height = 150
76
25
  const axisOffset = 20
@@ -113,7 +62,7 @@ const ResponseCurve = (props: ResponseCurveProps) => {
113
62
 
114
63
  const svgProps = { ref: svgRef }
115
64
 
116
- const responseCurves = RESPONSE_CURVES.map(
65
+ const responseCurves = origResponseCurves.map(
117
66
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: <explanation>
118
67
  ({ value, label }): ResponseCurve => {
119
68
  let c1 = 0
@@ -125,55 +74,55 @@ const ResponseCurve = (props: ResponseCurveProps) => {
125
74
  let labelX = xMid
126
75
  let labelY = yMid
127
76
  switch (value) {
128
- case RESPONSE_CURVE_0:
77
+ case responseCurves[0].value:
129
78
  c1 = xMid
130
79
  c2 = yMid
131
80
  labelY += 3
132
81
 
133
82
  break
134
- case RESPONSE_CURVE_1:
83
+ case responseCurves[1].value:
135
84
  c1 = inverted ? xMid + width * 0.13 : xMid - width * 0.13
136
85
  c2 = yMid - height * 0.13
137
86
  labelX = inverted ? xMid + width * 0.1 : xMid - width * 0.1
138
87
  labelY = yMid - height * 0.09
139
88
  break
140
89
 
141
- case RESPONSE_CURVE_2:
90
+ case responseCurves[2].value:
142
91
  c1 = inverted ? xMid + width * 0.25 : xMid - width * 0.25
143
92
  c2 = yMid - height * 0.25
144
93
  labelX = inverted ? xMid + width * 0.2 : xMid - width * 0.2
145
94
  labelY = yMid - height * 0.17
146
95
  break
147
96
 
148
- case RESPONSE_CURVE_3:
97
+ case responseCurves[3].value:
149
98
  c1 = inverted ? xMid + width * 0.35 : xMid - width * 0.35
150
99
  c2 = yMid - height * 0.35
151
100
  labelX = inverted ? xMid + width * 0.28 : xMid - width * 0.28
152
101
  labelY = yMid - height * 0.25
153
102
  break
154
103
 
155
- case RESPONSE_CURVE_4:
104
+ case responseCurves[4].value:
156
105
  c1 = inverted ? xMid - width * 0.13 : xMid + width * 0.13
157
106
  c2 = yMid + height * 0.13
158
107
  labelX = inverted ? xMid - width * 0.1 : xMid + width * 0.1
159
108
  labelY = yMid + height * 0.1
160
109
  break
161
110
 
162
- case RESPONSE_CURVE_5:
111
+ case responseCurves[5].value:
163
112
  c1 = inverted ? xMid - width * 0.25 : xMid + width * 0.25
164
113
  c2 = yMid + height * 0.25
165
114
  labelX = inverted ? xMid - width * 0.2 : xMid + width * 0.2
166
115
  labelY = yMid + height * 0.18
167
116
  break
168
117
 
169
- case RESPONSE_CURVE_6:
118
+ case responseCurves[6].value:
170
119
  c1 = inverted ? xMid - width * 0.35 : xMid + width * 0.35
171
120
  c2 = yMid + height * 0.35
172
121
  labelX = inverted ? xMid - width * 0.28 : xMid + width * 0.28
173
122
  labelY = yMid + height * 0.25
174
123
  break
175
124
 
176
- case RESPONSE_CURVE_7:
125
+ case responseCurves[7].value:
177
126
  x1 = inverted ? axisX1 : axisX2
178
127
  y1 = axisY1
179
128
  x2 = x1
@@ -299,6 +248,4 @@ const ResponseCurve = (props: ResponseCurveProps) => {
299
248
 
300
249
  export default ResponseCurve
301
250
 
302
- export { RESPONSE_CURVES }
303
-
304
- export type { Curve, ResponseCurve, ResponseCurveProps }
251
+ export type { ResponseCurve, ResponseCurveProps }
@@ -1,8 +1,9 @@
1
1
  import { forwardRef, useCallback } from 'react'
2
2
  import type { GroupBase, SelectInstance } from 'react-select'
3
+ import { type Curve, responseCurves } from '../midi/export'
3
4
  import DefaultTooltip, { type TooltipProps } from '../other/DefaultTooltip'
4
5
  import { findObj } from '../utils'
5
- import ResponseCurve, { type Curve, RESPONSE_CURVES } from './ResponseCurve'
6
+ import ResponseCurve from './ResponseCurve'
6
7
  import Select from './Select'
7
8
  import type { Option, SelectProps } from './Select'
8
9
 
@@ -32,7 +33,7 @@ const ResponseCurvePicker = forwardRef<
32
33
  const Placeholder = useCallback(
33
34
  () => (
34
35
  <div className="singleValue">
35
- {(findObj('value', value)(RESPONSE_CURVES) as Option<Curve>)?.label}
36
+ {(findObj('value', value)(responseCurves) as Option<Curve>)?.label}
36
37
  </div>
37
38
  ),
38
39
  [value],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zds-pickers",
3
- "version": "4.0.12",
3
+ "version": "4.0.13",
4
4
  "main": "./dist/index.cjs.js",
5
5
  "module": "./dist/index.es.js",
6
6
  "types": "./dist/types/index.d.ts",