@react-x11/components 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +979 -21
- package/dist/ansi/cast.d.ts +48 -0
- package/dist/ansi/cast.d.ts.map +1 -0
- package/dist/ansi/cast.js +135 -0
- package/dist/ansi/cast.js.map +1 -0
- package/dist/ansi/index.d.ts +10 -0
- package/dist/ansi/index.d.ts.map +1 -0
- package/dist/ansi/index.js +27 -0
- package/dist/ansi/index.js.map +1 -0
- package/dist/ansi/palette.d.ts +79 -0
- package/dist/ansi/palette.d.ts.map +1 -0
- package/dist/ansi/palette.js +155 -0
- package/dist/ansi/palette.js.map +1 -0
- package/dist/ansi/parse.d.ts +114 -0
- package/dist/ansi/parse.d.ts.map +1 -0
- package/dist/ansi/parse.js +687 -0
- package/dist/ansi/parse.js.map +1 -0
- package/dist/ansi/sgr.d.ts +87 -0
- package/dist/ansi/sgr.d.ts.map +1 -0
- package/dist/ansi/sgr.js +302 -0
- package/dist/ansi/sgr.js.map +1 -0
- package/dist/ansi/utf8.d.ts +15 -0
- package/dist/ansi/utf8.d.ts.map +1 -0
- package/dist/ansi/utf8.js +82 -0
- package/dist/ansi/utf8.js.map +1 -0
- package/dist/calendar/Calendar.d.ts +136 -0
- package/dist/calendar/Calendar.d.ts.map +1 -0
- package/dist/calendar/Calendar.js +460 -0
- package/dist/calendar/Calendar.js.map +1 -0
- package/dist/calendar/DatePicker.d.ts +52 -0
- package/dist/calendar/DatePicker.d.ts.map +1 -0
- package/dist/calendar/DatePicker.js +257 -0
- package/dist/calendar/DatePicker.js.map +1 -0
- package/dist/calendar/dates.d.ts +90 -0
- package/dist/calendar/dates.d.ts.map +1 -0
- package/dist/calendar/dates.js +236 -0
- package/dist/calendar/dates.js.map +1 -0
- package/dist/calendar/index.d.ts +8 -0
- package/dist/calendar/index.d.ts.map +1 -0
- package/dist/calendar/index.js +15 -0
- package/dist/calendar/index.js.map +1 -0
- package/dist/charts/components.d.ts +141 -0
- package/dist/charts/components.d.ts.map +1 -0
- package/dist/charts/components.js +580 -0
- package/dist/charts/components.js.map +1 -0
- package/dist/charts/data.d.ts +198 -0
- package/dist/charts/data.d.ts.map +1 -0
- package/dist/charts/data.js +616 -0
- package/dist/charts/data.js.map +1 -0
- package/dist/charts/hx.d.ts +21 -0
- package/dist/charts/hx.d.ts.map +1 -0
- package/dist/charts/hx.js +15 -0
- package/dist/charts/hx.js.map +1 -0
- package/dist/charts/index.d.ts +27 -0
- package/dist/charts/index.d.ts.map +1 -0
- package/dist/charts/index.js +38 -0
- package/dist/charts/index.js.map +1 -0
- package/dist/charts/node.d.ts +96 -0
- package/dist/charts/node.d.ts.map +1 -0
- package/dist/charts/node.js +720 -0
- package/dist/charts/node.js.map +1 -0
- package/dist/charts/render.d.ts +153 -0
- package/dist/charts/render.d.ts.map +1 -0
- package/dist/charts/render.js +762 -0
- package/dist/charts/render.js.map +1 -0
- package/dist/charts/scale.d.ts +42 -0
- package/dist/charts/scale.d.ts.map +1 -0
- package/dist/charts/scale.js +173 -0
- package/dist/charts/scale.js.map +1 -0
- package/dist/charts/spec.d.ts +91 -0
- package/dist/charts/spec.d.ts.map +1 -0
- package/dist/charts/spec.js +33 -0
- package/dist/charts/spec.js.map +1 -0
- package/dist/charts/timers.d.ts +6 -0
- package/dist/charts/timers.d.ts.map +1 -0
- package/dist/charts/timers.js +14 -0
- package/dist/charts/timers.js.map +1 -0
- package/dist/code/hx.d.ts +24 -0
- package/dist/code/hx.d.ts.map +1 -0
- package/dist/code/hx.js +25 -0
- package/dist/code/hx.js.map +1 -0
- package/dist/code/index.d.ts +45 -0
- package/dist/code/index.d.ts.map +1 -0
- package/dist/code/index.js +93 -0
- package/dist/code/index.js.map +1 -0
- package/dist/code-editor/completion.d.ts +26 -0
- package/dist/code-editor/completion.d.ts.map +1 -0
- package/dist/code-editor/completion.js +129 -0
- package/dist/code-editor/completion.js.map +1 -0
- package/dist/code-editor/doc.d.ts +35 -0
- package/dist/code-editor/doc.d.ts.map +1 -0
- package/dist/code-editor/doc.js +162 -0
- package/dist/code-editor/doc.js.map +1 -0
- package/dist/code-editor/hx.d.ts +13 -0
- package/dist/code-editor/hx.d.ts.map +1 -0
- package/dist/code-editor/hx.js +10 -0
- package/dist/code-editor/hx.js.map +1 -0
- package/dist/code-editor/index.d.ts +88 -0
- package/dist/code-editor/index.d.ts.map +1 -0
- package/dist/code-editor/index.js +401 -0
- package/dist/code-editor/index.js.map +1 -0
- package/dist/code-editor/node.d.ts +343 -0
- package/dist/code-editor/node.d.ts.map +1 -0
- package/dist/code-editor/node.js +1521 -0
- package/dist/code-editor/node.js.map +1 -0
- package/dist/code-language/hljs.d.ts +47 -0
- package/dist/code-language/hljs.d.ts.map +1 -0
- package/dist/code-language/hljs.js +211 -0
- package/dist/code-language/hljs.js.map +1 -0
- package/dist/code-language/index.d.ts +22 -0
- package/dist/code-language/index.d.ts.map +1 -0
- package/dist/code-language/index.js +20 -0
- package/dist/code-language/index.js.map +1 -0
- package/dist/code-language/languages/glsl.d.ts +4 -0
- package/dist/code-language/languages/glsl.d.ts.map +1 -0
- package/dist/code-language/languages/glsl.js +99 -0
- package/dist/code-language/languages/glsl.js.map +1 -0
- package/dist/code-language/languages/javascript.d.ts +10 -0
- package/dist/code-language/languages/javascript.d.ts.map +1 -0
- package/dist/code-language/languages/javascript.js +360 -0
- package/dist/code-language/languages/javascript.js.map +1 -0
- package/dist/code-language/languages/json.d.ts +4 -0
- package/dist/code-language/languages/json.d.ts.map +1 -0
- package/dist/code-language/languages/json.js +68 -0
- package/dist/code-language/languages/json.js.map +1 -0
- package/dist/code-language/languages/shell.d.ts +4 -0
- package/dist/code-language/languages/shell.d.ts.map +1 -0
- package/dist/code-language/languages/shell.js +189 -0
- package/dist/code-language/languages/shell.js.map +1 -0
- package/dist/code-language/languages/sql.d.ts +11 -0
- package/dist/code-language/languages/sql.d.ts.map +1 -0
- package/dist/code-language/languages/sql.js +133 -0
- package/dist/code-language/languages/sql.js.map +1 -0
- package/dist/code-language/lezer.d.ts +24 -0
- package/dist/code-language/lezer.d.ts.map +1 -0
- package/dist/code-language/lezer.js +148 -0
- package/dist/code-language/lezer.js.map +1 -0
- package/dist/code-language/registry.d.ts +19 -0
- package/dist/code-language/registry.d.ts.map +1 -0
- package/dist/code-language/registry.js +56 -0
- package/dist/code-language/registry.js.map +1 -0
- package/dist/code-language/runs.d.ts +35 -0
- package/dist/code-language/runs.d.ts.map +1 -0
- package/dist/code-language/runs.js +88 -0
- package/dist/code-language/runs.js.map +1 -0
- package/dist/code-language/stream.d.ts +70 -0
- package/dist/code-language/stream.d.ts.map +1 -0
- package/dist/code-language/stream.js +243 -0
- package/dist/code-language/stream.js.map +1 -0
- package/dist/code-language/textmate.d.ts +27 -0
- package/dist/code-language/textmate.d.ts.map +1 -0
- package/dist/code-language/textmate.js +86 -0
- package/dist/code-language/textmate.js.map +1 -0
- package/dist/code-language/theme.d.ts +26 -0
- package/dist/code-language/theme.d.ts.map +1 -0
- package/dist/code-language/theme.js +108 -0
- package/dist/code-language/theme.js.map +1 -0
- package/dist/code-language/timers.d.ts +7 -0
- package/dist/code-language/timers.d.ts.map +1 -0
- package/dist/code-language/timers.js +22 -0
- package/dist/code-language/timers.js.map +1 -0
- package/dist/code-language/types.d.ts +173 -0
- package/dist/code-language/types.d.ts.map +1 -0
- package/dist/code-language/types.js +41 -0
- package/dist/code-language/types.js.map +1 -0
- package/dist/codeblock/index.d.ts +69 -0
- package/dist/codeblock/index.d.ts.map +1 -0
- package/dist/codeblock/index.js +85 -0
- package/dist/codeblock/index.js.map +1 -0
- package/dist/color-picker/ColorField.d.ts +39 -0
- package/dist/color-picker/ColorField.d.ts.map +1 -0
- package/dist/color-picker/ColorField.js +239 -0
- package/dist/color-picker/ColorField.js.map +1 -0
- package/dist/color-picker/ColorPicker.d.ts +109 -0
- package/dist/color-picker/ColorPicker.d.ts.map +1 -0
- package/dist/color-picker/ColorPicker.js +757 -0
- package/dist/color-picker/ColorPicker.js.map +1 -0
- package/dist/color-picker/color.d.ts +105 -0
- package/dist/color-picker/color.d.ts.map +1 -0
- package/dist/color-picker/color.js +313 -0
- package/dist/color-picker/color.js.map +1 -0
- package/dist/color-picker/index.d.ts +8 -0
- package/dist/color-picker/index.d.ts.map +1 -0
- package/dist/color-picker/index.js +19 -0
- package/dist/color-picker/index.js.map +1 -0
- package/dist/desktop-calendar/eds.d.ts +102 -0
- package/dist/desktop-calendar/eds.d.ts.map +1 -0
- package/dist/desktop-calendar/eds.js +356 -0
- package/dist/desktop-calendar/eds.js.map +1 -0
- package/dist/desktop-calendar/ical.d.ts +63 -0
- package/dist/desktop-calendar/ical.d.ts.map +1 -0
- package/dist/desktop-calendar/ical.js +57 -0
- package/dist/desktop-calendar/ical.js.map +1 -0
- package/dist/desktop-calendar/index.d.ts +72 -0
- package/dist/desktop-calendar/index.d.ts.map +1 -0
- package/dist/desktop-calendar/index.js +213 -0
- package/dist/desktop-calendar/index.js.map +1 -0
- package/dist/embed/client.d.ts +121 -0
- package/dist/embed/client.d.ts.map +1 -0
- package/dist/embed/client.js +203 -0
- package/dist/embed/client.js.map +1 -0
- package/dist/embed/host.d.ts +96 -0
- package/dist/embed/host.d.ts.map +1 -0
- package/dist/embed/host.js +266 -0
- package/dist/embed/host.js.map +1 -0
- package/dist/embed/index.d.ts +5 -0
- package/dist/embed/index.d.ts.map +1 -0
- package/dist/embed/index.js +13 -0
- package/dist/embed/index.js.map +1 -0
- package/dist/embed/timers.d.ts +6 -0
- package/dist/embed/timers.d.ts.map +1 -0
- package/dist/embed/timers.js +16 -0
- package/dist/embed/timers.js.map +1 -0
- package/dist/flow/draw.d.ts +45 -0
- package/dist/flow/draw.d.ts.map +1 -0
- package/dist/flow/draw.js +295 -0
- package/dist/flow/draw.js.map +1 -0
- package/dist/flow/index.d.ts +64 -0
- package/dist/flow/index.d.ts.map +1 -0
- package/dist/flow/index.js +306 -0
- package/dist/flow/index.js.map +1 -0
- package/dist/flow/model.d.ts +158 -0
- package/dist/flow/model.d.ts.map +1 -0
- package/dist/flow/model.js +566 -0
- package/dist/flow/model.js.map +1 -0
- package/dist/flow/node.d.ts +429 -0
- package/dist/flow/node.d.ts.map +1 -0
- package/dist/flow/node.js +3025 -0
- package/dist/flow/node.js.map +1 -0
- package/dist/flow/paths.d.ts +43 -0
- package/dist/flow/paths.d.ts.map +1 -0
- package/dist/flow/paths.js +327 -0
- package/dist/flow/paths.js.map +1 -0
- package/dist/flow/types.d.ts +561 -0
- package/dist/flow/types.d.ts.map +1 -0
- package/dist/flow/types.js +2 -0
- package/dist/flow/types.js.map +1 -0
- package/dist/formula/hx.d.ts +24 -0
- package/dist/formula/hx.d.ts.map +1 -0
- package/dist/formula/hx.js +25 -0
- package/dist/formula/hx.js.map +1 -0
- package/dist/formula/index.d.ts +74 -0
- package/dist/formula/index.d.ts.map +1 -0
- package/dist/formula/index.js +155 -0
- package/dist/formula/index.js.map +1 -0
- package/dist/formula/katex.d.ts +78 -0
- package/dist/formula/katex.d.ts.map +1 -0
- package/dist/formula/katex.js +130 -0
- package/dist/formula/katex.js.map +1 -0
- package/dist/formula/layout.d.ts +103 -0
- package/dist/formula/layout.d.ts.map +1 -0
- package/dist/formula/layout.js +716 -0
- package/dist/formula/layout.js.map +1 -0
- package/dist/formula/node.d.ts +50 -0
- package/dist/formula/node.d.ts.map +1 -0
- package/dist/formula/node.js +351 -0
- package/dist/formula/node.js.map +1 -0
- package/dist/html/controls.d.ts +48 -0
- package/dist/html/controls.d.ts.map +1 -0
- package/dist/html/controls.js +195 -0
- package/dist/html/controls.js.map +1 -0
- package/dist/html/css/cascade.d.ts +51 -0
- package/dist/html/css/cascade.d.ts.map +1 -0
- package/dist/html/css/cascade.js +552 -0
- package/dist/html/css/cascade.js.map +1 -0
- package/dist/html/css/parse.d.ts +74 -0
- package/dist/html/css/parse.d.ts.map +1 -0
- package/dist/html/css/parse.js +464 -0
- package/dist/html/css/parse.js.map +1 -0
- package/dist/html/css/style.d.ts +142 -0
- package/dist/html/css/style.d.ts.map +1 -0
- package/dist/html/css/style.js +1145 -0
- package/dist/html/css/style.js.map +1 -0
- package/dist/html/css/ua.d.ts +5 -0
- package/dist/html/css/ua.d.ts.map +1 -0
- package/dist/html/css/ua.js +171 -0
- package/dist/html/css/ua.js.map +1 -0
- package/dist/html/css/values.d.ts +78 -0
- package/dist/html/css/values.d.ts.map +1 -0
- package/dist/html/css/values.js +330 -0
- package/dist/html/css/values.js.map +1 -0
- package/dist/html/dom.d.ts +112 -0
- package/dist/html/dom.d.ts.map +1 -0
- package/dist/html/dom.js +374 -0
- package/dist/html/dom.js.map +1 -0
- package/dist/html/hx.d.ts +24 -0
- package/dist/html/hx.d.ts.map +1 -0
- package/dist/html/hx.js +29 -0
- package/dist/html/hx.js.map +1 -0
- package/dist/html/index.d.ts +137 -0
- package/dist/html/index.d.ts.map +1 -0
- package/dist/html/index.js +339 -0
- package/dist/html/index.js.map +1 -0
- package/dist/html/layout/block.d.ts +58 -0
- package/dist/html/layout/block.d.ts.map +1 -0
- package/dist/html/layout/block.js +724 -0
- package/dist/html/layout/block.js.map +1 -0
- package/dist/html/layout/boxes.d.ts +261 -0
- package/dist/html/layout/boxes.d.ts.map +1 -0
- package/dist/html/layout/boxes.js +725 -0
- package/dist/html/layout/boxes.js.map +1 -0
- package/dist/html/layout/flex.d.ts +16 -0
- package/dist/html/layout/flex.d.ts.map +1 -0
- package/dist/html/layout/flex.js +242 -0
- package/dist/html/layout/flex.js.map +1 -0
- package/dist/html/layout/floats.d.ts +50 -0
- package/dist/html/layout/floats.d.ts.map +1 -0
- package/dist/html/layout/floats.js +110 -0
- package/dist/html/layout/floats.js.map +1 -0
- package/dist/html/layout/inline.d.ts +44 -0
- package/dist/html/layout/inline.d.ts.map +1 -0
- package/dist/html/layout/inline.js +700 -0
- package/dist/html/layout/inline.js.map +1 -0
- package/dist/html/layout/table.d.ts +5 -0
- package/dist/html/layout/table.d.ts.map +1 -0
- package/dist/html/layout/table.js +340 -0
- package/dist/html/layout/table.js.map +1 -0
- package/dist/html/node.d.ts +149 -0
- package/dist/html/node.d.ts.map +1 -0
- package/dist/html/node.js +861 -0
- package/dist/html/node.js.map +1 -0
- package/dist/html/paint.d.ts +48 -0
- package/dist/html/paint.d.ts.map +1 -0
- package/dist/html/paint.js +495 -0
- package/dist/html/paint.js.map +1 -0
- package/dist/html/resources.d.ts +48 -0
- package/dist/html/resources.d.ts.map +1 -0
- package/dist/html/resources.js +156 -0
- package/dist/html/resources.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +92 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/heights.d.ts +88 -0
- package/dist/internal/heights.d.ts.map +1 -0
- package/dist/internal/heights.js +203 -0
- package/dist/internal/heights.js.map +1 -0
- package/dist/internal/hx.d.ts +24 -0
- package/dist/internal/hx.d.ts.map +1 -0
- package/dist/internal/hx.js +27 -0
- package/dist/internal/hx.js.map +1 -0
- package/dist/internal/scroll.d.ts +62 -0
- package/dist/internal/scroll.d.ts.map +1 -0
- package/dist/internal/scroll.js +224 -0
- package/dist/internal/scroll.js.map +1 -0
- package/dist/internal/text.d.ts +6 -0
- package/dist/internal/text.d.ts.map +1 -0
- package/dist/internal/text.js +44 -0
- package/dist/internal/text.js.map +1 -0
- package/dist/internal/timers.d.ts +8 -0
- package/dist/internal/timers.d.ts.map +1 -0
- package/dist/internal/timers.js +22 -0
- package/dist/internal/timers.js.map +1 -0
- package/dist/internal/widget.d.ts +40 -0
- package/dist/internal/widget.d.ts.map +1 -0
- package/dist/internal/widget.js +44 -0
- package/dist/internal/widget.js.map +1 -0
- package/dist/markdown/ast.d.ts +126 -0
- package/dist/markdown/ast.d.ts.map +1 -0
- package/dist/markdown/ast.js +8 -0
- package/dist/markdown/ast.js.map +1 -0
- package/dist/markdown/hx.d.ts +24 -0
- package/dist/markdown/hx.d.ts.map +1 -0
- package/dist/markdown/hx.js +25 -0
- package/dist/markdown/hx.js.map +1 -0
- package/dist/markdown/index.d.ts +90 -0
- package/dist/markdown/index.d.ts.map +1 -0
- package/dist/markdown/index.js +413 -0
- package/dist/markdown/index.js.map +1 -0
- package/dist/markdown/parse.d.ts +8 -0
- package/dist/markdown/parse.d.ts.map +1 -0
- package/dist/markdown/parse.js +911 -0
- package/dist/markdown/parse.js.map +1 -0
- package/dist/markdown/spans.d.ts +20 -0
- package/dist/markdown/spans.d.ts.map +1 -0
- package/dist/markdown/spans.js +96 -0
- package/dist/markdown/spans.js.map +1 -0
- package/dist/media-player/backends.d.ts +64 -0
- package/dist/media-player/backends.d.ts.map +1 -0
- package/dist/media-player/backends.js +110 -0
- package/dist/media-player/backends.js.map +1 -0
- package/dist/media-player/control.d.ts +40 -0
- package/dist/media-player/control.d.ts.map +1 -0
- package/dist/media-player/control.js +44 -0
- package/dist/media-player/control.js.map +1 -0
- package/dist/media-player/hx.d.ts +24 -0
- package/dist/media-player/hx.d.ts.map +1 -0
- package/dist/media-player/hx.js +25 -0
- package/dist/media-player/hx.js.map +1 -0
- package/dist/media-player/index.d.ts +107 -0
- package/dist/media-player/index.d.ts.map +1 -0
- package/dist/media-player/index.js +219 -0
- package/dist/media-player/index.js.map +1 -0
- package/dist/media-player/mpv.d.ts +4 -0
- package/dist/media-player/mpv.d.ts.map +1 -0
- package/dist/media-player/mpv.js +120 -0
- package/dist/media-player/mpv.js.map +1 -0
- package/dist/media-player/vlc.d.ts +8 -0
- package/dist/media-player/vlc.d.ts.map +1 -0
- package/dist/media-player/vlc.js +83 -0
- package/dist/media-player/vlc.js.map +1 -0
- package/dist/richtext/index.d.ts +19 -0
- package/dist/richtext/index.d.ts.map +1 -0
- package/dist/richtext/index.js +4 -0
- package/dist/richtext/index.js.map +1 -0
- package/dist/richtext/links.d.ts +12 -0
- package/dist/richtext/links.d.ts.map +1 -0
- package/dist/richtext/links.js +64 -0
- package/dist/richtext/links.js.map +1 -0
- package/dist/richtext/menu.d.ts +11 -0
- package/dist/richtext/menu.d.ts.map +1 -0
- package/dist/richtext/menu.js +43 -0
- package/dist/richtext/menu.js.map +1 -0
- package/dist/richtext/node.d.ts +151 -0
- package/dist/richtext/node.d.ts.map +1 -0
- package/dist/richtext/node.js +255 -0
- package/dist/richtext/node.js.map +1 -0
- package/dist/richtext/runs.d.ts +92 -0
- package/dist/richtext/runs.d.ts.map +1 -0
- package/dist/richtext/runs.js +158 -0
- package/dist/richtext/runs.js.map +1 -0
- package/dist/table/hx.d.ts +24 -0
- package/dist/table/hx.d.ts.map +1 -0
- package/dist/table/hx.js +25 -0
- package/dist/table/hx.js.map +1 -0
- package/dist/table/index.d.ts +169 -0
- package/dist/table/index.d.ts.map +1 -0
- package/dist/table/index.js +890 -0
- package/dist/table/index.js.map +1 -0
- package/dist/table/rows.d.ts +136 -0
- package/dist/table/rows.d.ts.map +1 -0
- package/dist/table/rows.js +146 -0
- package/dist/table/rows.js.map +1 -0
- package/dist/terminal/backends.d.ts +105 -0
- package/dist/terminal/backends.d.ts.map +1 -0
- package/dist/terminal/backends.js +185 -0
- package/dist/terminal/backends.js.map +1 -0
- package/dist/terminal/hx.d.ts +24 -0
- package/dist/terminal/hx.d.ts.map +1 -0
- package/dist/terminal/hx.js +25 -0
- package/dist/terminal/hx.js.map +1 -0
- package/dist/terminal/index.d.ts +160 -0
- package/dist/terminal/index.d.ts.map +1 -0
- package/dist/terminal/index.js +344 -0
- package/dist/terminal/index.js.map +1 -0
- package/dist/terminal/title.d.ts +24 -0
- package/dist/terminal/title.d.ts.map +1 -0
- package/dist/terminal/title.js +129 -0
- package/dist/terminal/title.js.map +1 -0
- package/dist/terminal/vt/colors.d.ts +63 -0
- package/dist/terminal/vt/colors.d.ts.map +1 -0
- package/dist/terminal/vt/colors.js +203 -0
- package/dist/terminal/vt/colors.js.map +1 -0
- package/dist/terminal/vt/diff.d.ts +117 -0
- package/dist/terminal/vt/diff.d.ts.map +1 -0
- package/dist/terminal/vt/diff.js +358 -0
- package/dist/terminal/vt/diff.js.map +1 -0
- package/dist/terminal/vt/fonts.d.ts +92 -0
- package/dist/terminal/vt/fonts.d.ts.map +1 -0
- package/dist/terminal/vt/fonts.js +178 -0
- package/dist/terminal/vt/fonts.js.map +1 -0
- package/dist/terminal/vt/index.d.ts +78 -0
- package/dist/terminal/vt/index.d.ts.map +1 -0
- package/dist/terminal/vt/index.js +312 -0
- package/dist/terminal/vt/index.js.map +1 -0
- package/dist/terminal/vt/keys.d.ts +74 -0
- package/dist/terminal/vt/keys.d.ts.map +1 -0
- package/dist/terminal/vt/keys.js +309 -0
- package/dist/terminal/vt/keys.js.map +1 -0
- package/dist/terminal/vt/mouse.d.ts +44 -0
- package/dist/terminal/vt/mouse.d.ts.map +1 -0
- package/dist/terminal/vt/mouse.js +106 -0
- package/dist/terminal/vt/mouse.js.map +1 -0
- package/dist/terminal/vt/node.d.ts +246 -0
- package/dist/terminal/vt/node.d.ts.map +1 -0
- package/dist/terminal/vt/node.js +1068 -0
- package/dist/terminal/vt/node.js.map +1 -0
- package/dist/terminal/vt/pty.d.ts +81 -0
- package/dist/terminal/vt/pty.d.ts.map +1 -0
- package/dist/terminal/vt/pty.js +201 -0
- package/dist/terminal/vt/pty.js.map +1 -0
- package/dist/terminal/vt/renderer.d.ts +179 -0
- package/dist/terminal/vt/renderer.d.ts.map +1 -0
- package/dist/terminal/vt/renderer.js +357 -0
- package/dist/terminal/vt/renderer.js.map +1 -0
- package/dist/terminal/vt/timers.d.ts +6 -0
- package/dist/terminal/vt/timers.d.ts.map +1 -0
- package/dist/terminal/vt/timers.js +16 -0
- package/dist/terminal/vt/timers.js.map +1 -0
- package/dist/terminal/vt/xterm.d.ts +142 -0
- package/dist/terminal/vt/xterm.d.ts.map +1 -0
- package/dist/terminal/vt/xterm.js +32 -0
- package/dist/terminal/vt/xterm.js.map +1 -0
- package/dist/terminal-output/hx.d.ts +24 -0
- package/dist/terminal-output/hx.d.ts.map +1 -0
- package/dist/terminal-output/hx.js +25 -0
- package/dist/terminal-output/hx.js.map +1 -0
- package/dist/terminal-output/index.d.ts +92 -0
- package/dist/terminal-output/index.d.ts.map +1 -0
- package/dist/terminal-output/index.js +179 -0
- package/dist/terminal-output/index.js.map +1 -0
- package/dist/terminal-output/runs.d.ts +27 -0
- package/dist/terminal-output/runs.d.ts.map +1 -0
- package/dist/terminal-output/runs.js +66 -0
- package/dist/terminal-output/runs.js.map +1 -0
- package/dist/three/canvas.d.ts +46 -0
- package/dist/three/canvas.d.ts.map +1 -0
- package/dist/three/canvas.js +305 -0
- package/dist/three/canvas.js.map +1 -0
- package/dist/three/events.d.ts +64 -0
- package/dist/three/events.d.ts.map +1 -0
- package/dist/three/events.js +146 -0
- package/dist/three/events.js.map +1 -0
- package/dist/three/geometries.d.ts +89 -0
- package/dist/three/geometries.d.ts.map +1 -0
- package/dist/three/geometries.js +345 -0
- package/dist/three/geometries.js.map +1 -0
- package/dist/three/globals.d.ts +7 -0
- package/dist/three/globals.d.ts.map +1 -0
- package/dist/three/globals.js +20 -0
- package/dist/three/globals.js.map +1 -0
- package/dist/three/hx.d.ts +9 -0
- package/dist/three/hx.d.ts.map +1 -0
- package/dist/three/hx.js +10 -0
- package/dist/three/hx.js.map +1 -0
- package/dist/three/index.d.ts +22 -0
- package/dist/three/index.d.ts.map +1 -0
- package/dist/three/index.js +24 -0
- package/dist/three/index.js.map +1 -0
- package/dist/three/jsx-dev-runtime.d.ts +19 -0
- package/dist/three/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/three/jsx-dev-runtime.js +2 -0
- package/dist/three/jsx-dev-runtime.js.map +1 -0
- package/dist/three/jsx-runtime.d.ts +19 -0
- package/dist/three/jsx-runtime.d.ts.map +1 -0
- package/dist/three/jsx-runtime.js +2 -0
- package/dist/three/jsx-runtime.js.map +1 -0
- package/dist/three/jsx.d.ts +198 -0
- package/dist/three/jsx.d.ts.map +1 -0
- package/dist/three/jsx.js +2 -0
- package/dist/three/jsx.js.map +1 -0
- package/dist/three/materials.d.ts +125 -0
- package/dist/three/materials.d.ts.map +1 -0
- package/dist/three/materials.js +229 -0
- package/dist/three/materials.js.map +1 -0
- package/dist/three/math.d.ts +146 -0
- package/dist/three/math.d.ts.map +1 -0
- package/dist/three/math.js +464 -0
- package/dist/three/math.js.map +1 -0
- package/dist/three/objects.d.ts +185 -0
- package/dist/three/objects.d.ts.map +1 -0
- package/dist/three/objects.js +309 -0
- package/dist/three/objects.js.map +1 -0
- package/dist/three/passes.d.ts +54 -0
- package/dist/three/passes.d.ts.map +1 -0
- package/dist/three/passes.js +78 -0
- package/dist/three/passes.js.map +1 -0
- package/dist/three/postprocess.d.ts +85 -0
- package/dist/three/postprocess.d.ts.map +1 -0
- package/dist/three/postprocess.js +503 -0
- package/dist/three/postprocess.js.map +1 -0
- package/dist/three/raycast.d.ts +24 -0
- package/dist/three/raycast.d.ts.map +1 -0
- package/dist/three/raycast.js +138 -0
- package/dist/three/raycast.js.map +1 -0
- package/dist/three/reconciler.d.ts +48 -0
- package/dist/three/reconciler.d.ts.map +1 -0
- package/dist/three/reconciler.js +416 -0
- package/dist/three/reconciler.js.map +1 -0
- package/dist/three/renderer-direct.d.ts +102 -0
- package/dist/three/renderer-direct.d.ts.map +1 -0
- package/dist/three/renderer-direct.js +782 -0
- package/dist/three/renderer-direct.js.map +1 -0
- package/dist/three/renderer-indirect.d.ts +68 -0
- package/dist/three/renderer-indirect.d.ts.map +1 -0
- package/dist/three/renderer-indirect.js +438 -0
- package/dist/three/renderer-indirect.js.map +1 -0
- package/dist/three/store.d.ts +81 -0
- package/dist/three/store.d.ts.map +1 -0
- package/dist/three/store.js +110 -0
- package/dist/three/store.js.map +1 -0
- package/dist/timeline/hx.d.ts +18 -0
- package/dist/timeline/hx.d.ts.map +1 -0
- package/dist/timeline/hx.js +10 -0
- package/dist/timeline/hx.js.map +1 -0
- package/dist/timeline/index.d.ts +152 -0
- package/dist/timeline/index.d.ts.map +1 -0
- package/dist/timeline/index.js +383 -0
- package/dist/timeline/index.js.map +1 -0
- package/dist/tray-host/hx.d.ts +24 -0
- package/dist/tray-host/hx.d.ts.map +1 -0
- package/dist/tray-host/hx.js +25 -0
- package/dist/tray-host/hx.js.map +1 -0
- package/dist/tray-host/index.d.ts +110 -0
- package/dist/tray-host/index.d.ts.map +1 -0
- package/dist/tray-host/index.js +191 -0
- package/dist/tray-host/index.js.map +1 -0
- package/dist/tray-host/manager.d.ts +137 -0
- package/dist/tray-host/manager.d.ts.map +1 -0
- package/dist/tray-host/manager.js +462 -0
- package/dist/tray-host/manager.js.map +1 -0
- package/dist/tray-host/notify.d.ts +22 -0
- package/dist/tray-host/notify.d.ts.map +1 -0
- package/dist/tray-host/notify.js +74 -0
- package/dist/tray-host/notify.js.map +1 -0
- package/dist/tray-host/protocol.d.ts +106 -0
- package/dist/tray-host/protocol.d.ts.map +1 -0
- package/dist/tray-host/protocol.js +191 -0
- package/dist/tray-host/protocol.js.map +1 -0
- package/dist/tree/hx.d.ts +24 -0
- package/dist/tree/hx.d.ts.map +1 -0
- package/dist/tree/hx.js +25 -0
- package/dist/tree/hx.js.map +1 -0
- package/dist/tree/index.d.ts +221 -0
- package/dist/tree/index.d.ts.map +1 -0
- package/dist/tree/index.js +751 -0
- package/dist/tree/index.js.map +1 -0
- package/dist/tree/internal.d.ts +18 -0
- package/dist/tree/internal.d.ts.map +1 -0
- package/dist/tree/internal.js +66 -0
- package/dist/tree/internal.js.map +1 -0
- package/dist/tree/rows.d.ts +177 -0
- package/dist/tree/rows.d.ts.map +1 -0
- package/dist/tree/rows.js +179 -0
- package/dist/tree/rows.js.map +1 -0
- package/package.json +166 -12
- package/src/ansi/cast.ts +159 -0
- package/src/ansi/index.ts +53 -0
- package/src/ansi/palette.ts +226 -0
- package/src/ansi/parse.ts +780 -0
- package/src/ansi/sgr.ts +380 -0
- package/src/ansi/utf8.ts +84 -0
- package/src/calendar/Calendar.ts +744 -0
- package/src/calendar/DatePicker.ts +368 -0
- package/src/calendar/dates.ts +307 -0
- package/src/calendar/index.ts +51 -0
- package/src/charts/components.ts +864 -0
- package/src/charts/data.ts +776 -0
- package/src/charts/hx.ts +39 -0
- package/src/charts/index.ts +99 -0
- package/src/charts/node.ts +932 -0
- package/src/charts/render.ts +982 -0
- package/src/charts/scale.ts +214 -0
- package/src/charts/spec.ts +122 -0
- package/src/charts/timers.ts +24 -0
- package/src/code/hx.ts +51 -0
- package/src/code/index.ts +174 -0
- package/src/code-editor/completion.ts +161 -0
- package/src/code-editor/doc.ts +198 -0
- package/src/code-editor/hx.ts +26 -0
- package/src/code-editor/index.ts +615 -0
- package/src/code-editor/node.ts +1926 -0
- package/src/code-language/hljs.ts +302 -0
- package/src/code-language/index.ts +51 -0
- package/src/code-language/languages/glsl.ts +120 -0
- package/src/code-language/languages/javascript.ts +419 -0
- package/src/code-language/languages/json.ts +72 -0
- package/src/code-language/languages/shell.ts +221 -0
- package/src/code-language/languages/sql.ts +165 -0
- package/src/code-language/lezer.ts +190 -0
- package/src/code-language/registry.ts +66 -0
- package/src/code-language/runs.ts +128 -0
- package/src/code-language/stream.ts +306 -0
- package/src/code-language/textmate.ts +134 -0
- package/src/code-language/theme.ts +124 -0
- package/src/code-language/timers.ts +36 -0
- package/src/code-language/types.ts +252 -0
- package/src/codeblock/index.ts +146 -0
- package/src/color-picker/ColorField.ts +333 -0
- package/src/color-picker/ColorPicker.ts +1069 -0
- package/src/color-picker/color.ts +399 -0
- package/src/color-picker/index.ts +50 -0
- package/src/desktop-calendar/eds.ts +484 -0
- package/src/desktop-calendar/ical.ts +119 -0
- package/src/desktop-calendar/index.ts +287 -0
- package/src/embed/client.ts +311 -0
- package/src/embed/host.ts +432 -0
- package/src/embed/index.ts +33 -0
- package/src/embed/timers.ts +32 -0
- package/src/flow/draw.ts +418 -0
- package/src/flow/index.ts +473 -0
- package/src/flow/model.ts +687 -0
- package/src/flow/node.ts +3694 -0
- package/src/flow/paths.ts +403 -0
- package/src/flow/types.ts +634 -0
- package/src/formula/hx.ts +51 -0
- package/src/formula/index.ts +243 -0
- package/src/formula/katex.ts +209 -0
- package/src/formula/layout.ts +876 -0
- package/src/formula/node.ts +467 -0
- package/src/html/controls.ts +244 -0
- package/src/html/css/cascade.ts +606 -0
- package/src/html/css/parse.ts +500 -0
- package/src/html/css/style.ts +1371 -0
- package/src/html/css/ua.ts +174 -0
- package/src/html/css/values.ts +358 -0
- package/src/html/dom.ts +410 -0
- package/src/html/hx.ts +55 -0
- package/src/html/index.ts +545 -0
- package/src/html/layout/block.ts +876 -0
- package/src/html/layout/boxes.ts +981 -0
- package/src/html/layout/flex.ts +297 -0
- package/src/html/layout/floats.ts +125 -0
- package/src/html/layout/inline.ts +870 -0
- package/src/html/layout/table.ts +380 -0
- package/src/html/node.ts +967 -0
- package/src/html/paint.ts +605 -0
- package/src/html/resources.ts +214 -0
- package/src/index.ts +638 -0
- package/src/internal/heights.ts +222 -0
- package/src/internal/hx.ts +53 -0
- package/src/internal/scroll.ts +288 -0
- package/src/internal/text.ts +44 -0
- package/src/internal/timers.ts +44 -0
- package/src/internal/widget.ts +92 -0
- package/src/markdown/ast.ts +163 -0
- package/src/markdown/hx.ts +51 -0
- package/src/markdown/index.ts +686 -0
- package/src/markdown/parse.ts +1037 -0
- package/src/markdown/spans.ts +143 -0
- package/src/media-player/backends.ts +155 -0
- package/src/media-player/control.ts +70 -0
- package/src/media-player/hx.ts +51 -0
- package/src/media-player/index.ts +378 -0
- package/src/media-player/mpv.ts +146 -0
- package/src/media-player/vlc.ts +97 -0
- package/src/richtext/index.ts +42 -0
- package/src/richtext/links.ts +78 -0
- package/src/richtext/menu.ts +49 -0
- package/src/richtext/node.ts +406 -0
- package/src/richtext/runs.ts +253 -0
- package/src/table/hx.ts +51 -0
- package/src/table/index.ts +1270 -0
- package/src/table/rows.ts +275 -0
- package/src/terminal/backends.ts +242 -0
- package/src/terminal/hx.ts +51 -0
- package/src/terminal/index.ts +574 -0
- package/src/terminal/title.ts +172 -0
- package/src/terminal/vt/colors.ts +247 -0
- package/src/terminal/vt/diff.ts +467 -0
- package/src/terminal/vt/fonts.ts +233 -0
- package/src/terminal/vt/index.ts +443 -0
- package/src/terminal/vt/keys.ts +369 -0
- package/src/terminal/vt/mouse.ts +144 -0
- package/src/terminal/vt/node.ts +1242 -0
- package/src/terminal/vt/pty.ts +334 -0
- package/src/terminal/vt/renderer.ts +555 -0
- package/src/terminal/vt/timers.ts +31 -0
- package/src/terminal/vt/xterm.ts +193 -0
- package/src/terminal-output/hx.ts +51 -0
- package/src/terminal-output/index.ts +340 -0
- package/src/terminal-output/runs.ts +79 -0
- package/src/three/canvas.ts +451 -0
- package/src/three/events.ts +197 -0
- package/src/three/geometries.ts +429 -0
- package/src/three/globals.ts +34 -0
- package/src/three/hx.ts +22 -0
- package/src/three/index.ts +98 -0
- package/src/three/jsx-dev-runtime.ts +27 -0
- package/src/three/jsx-runtime.ts +38 -0
- package/src/three/jsx.ts +275 -0
- package/src/three/materials.ts +270 -0
- package/src/three/math.ts +585 -0
- package/src/three/objects.ts +397 -0
- package/src/three/passes.ts +90 -0
- package/src/three/postprocess.ts +677 -0
- package/src/three/raycast.ts +189 -0
- package/src/three/react-reconciler.d.ts +50 -0
- package/src/three/reconciler.ts +624 -0
- package/src/three/renderer-direct.ts +1055 -0
- package/src/three/renderer-indirect.ts +570 -0
- package/src/three/store.ts +207 -0
- package/src/timeline/hx.ts +31 -0
- package/src/timeline/index.ts +603 -0
- package/src/tray-host/hx.ts +51 -0
- package/src/tray-host/index.ts +331 -0
- package/src/tray-host/manager.ts +639 -0
- package/src/tray-host/notify.ts +102 -0
- package/src/tray-host/protocol.ts +235 -0
- package/src/tree/hx.ts +51 -0
- package/src/tree/index.ts +1127 -0
- package/src/tree/internal.ts +87 -0
- package/src/tree/rows.ts +334 -0
- package/src/index.d.ts +0 -2
- package/src/index.js +0 -9
- package/src/sparkline/index.d.ts +0 -29
- package/src/sparkline/index.js +0 -50
- package/src/sparkline/node.js +0 -72
|
@@ -0,0 +1,1069 @@
|
|
|
1
|
+
// <ColorPicker> — a saturation/value field over a hue slider, and whatever
|
|
2
|
+
// else the app asked for.
|
|
3
|
+
//
|
|
4
|
+
// Nothing here registers an element. The question `src/flow/` established is
|
|
5
|
+
// whether the feature's viewport is a *transform*; a picker's is not, so this
|
|
6
|
+
// is the `<Calendar>` shape — `<box>`, `<text>`, `<textinput>` and three
|
|
7
|
+
// `<canvas>` panes — and importing it has no side effect at all.
|
|
8
|
+
//
|
|
9
|
+
// The three panes are pictures, and they are cheap ones: ntk's 2d context
|
|
10
|
+
// hands out real XRender gradients, so the field is a hue fill plus two
|
|
11
|
+
// gradients rather than 36 000 pixels of JavaScript, and each pane carries a
|
|
12
|
+
// `cacheKey` naming everything its drawing reads. The **thumbs are not part
|
|
13
|
+
// of the drawing** — each is an absolutely positioned `<box>` — so a drag
|
|
14
|
+
// moves two numbers in a style and repaints a 12px node, instead of
|
|
15
|
+
// re-running the gradients on every pointer motion.
|
|
16
|
+
//
|
|
17
|
+
// The panes are square-cornered on purpose: ntk's rounded-rect fast path
|
|
18
|
+
// bails to polygon rasterization when the fill is not a plain colour (the
|
|
19
|
+
// `gradient` reason in `stats.shapes`), and a picker is the surface most
|
|
20
|
+
// likely to hit that cliff.
|
|
21
|
+
import React, { useImperativeHandle, useRef, useState } from 'react';
|
|
22
|
+
import type { ReactElement, ReactNode, Ref } from 'react';
|
|
23
|
+
import { createStyles } from 'react-x11/style';
|
|
24
|
+
import type { Style } from 'react-x11/style';
|
|
25
|
+
import { useEyedropper, useTheme } from 'react-x11';
|
|
26
|
+
import type {
|
|
27
|
+
ChangeEvent,
|
|
28
|
+
DrawnNode,
|
|
29
|
+
KeyboardEvent,
|
|
30
|
+
MouseEvent,
|
|
31
|
+
TextInputNode,
|
|
32
|
+
} from 'react-x11';
|
|
33
|
+
import {
|
|
34
|
+
XK_DOWN,
|
|
35
|
+
XK_END,
|
|
36
|
+
XK_ESCAPE,
|
|
37
|
+
XK_HOME,
|
|
38
|
+
XK_LEFT,
|
|
39
|
+
XK_PAGE_DOWN,
|
|
40
|
+
XK_PAGE_UP,
|
|
41
|
+
XK_RETURN,
|
|
42
|
+
XK_RIGHT,
|
|
43
|
+
XK_TAB,
|
|
44
|
+
XK_UP,
|
|
45
|
+
} from 'react-x11/keysyms';
|
|
46
|
+
|
|
47
|
+
import { hx } from '../internal/hx.js';
|
|
48
|
+
import { changeEvent } from '../internal/widget.js';
|
|
49
|
+
import type { WidgetChangeEvent } from '../internal/widget.js';
|
|
50
|
+
import {
|
|
51
|
+
channelsFromHsv,
|
|
52
|
+
channelsFromRgb,
|
|
53
|
+
contrastGrade,
|
|
54
|
+
contrastRatio,
|
|
55
|
+
formatColor,
|
|
56
|
+
formatOf,
|
|
57
|
+
opaqueHex,
|
|
58
|
+
parseColor,
|
|
59
|
+
} from './color.js';
|
|
60
|
+
import type { ColorChannels, ColorFormat } from './color.js';
|
|
61
|
+
|
|
62
|
+
// The geometry. Fixed rather than fluid, for the reason `CALENDAR_WIDTH`
|
|
63
|
+
// exists: `<ColorField>` has to size a real X window around this *before* it
|
|
64
|
+
// is laid out, and it is also what lets the panes carry a `cacheKey` — a key
|
|
65
|
+
// naming a width the pane might not have is a stale picture.
|
|
66
|
+
const PAD = 10;
|
|
67
|
+
const GAP = 8;
|
|
68
|
+
const CONTENT = 240;
|
|
69
|
+
const AREA_H = 150;
|
|
70
|
+
const STRIP_H = 12;
|
|
71
|
+
const ROW_H = 26;
|
|
72
|
+
const SWATCH = 20;
|
|
73
|
+
const SWATCH_GAP = 6;
|
|
74
|
+
const THUMB = 12;
|
|
75
|
+
/** The checker under anything translucent, in device pixels. */
|
|
76
|
+
const CHECKER = 6;
|
|
77
|
+
|
|
78
|
+
/** How wide a `<ColorPicker>` lays out. */
|
|
79
|
+
export const COLOR_PICKER_WIDTH = CONTENT + PAD * 2;
|
|
80
|
+
|
|
81
|
+
const s = createStyles({
|
|
82
|
+
root: {
|
|
83
|
+
padding: PAD,
|
|
84
|
+
gap: GAP,
|
|
85
|
+
alignItems: 'stretch',
|
|
86
|
+
width: COLOR_PICKER_WIDTH,
|
|
87
|
+
// The geometry is a promise the panes' `cacheKey`s and the thumbs'
|
|
88
|
+
// positions are both written against, so the panel does not shrink: a
|
|
89
|
+
// squashed field would put the thumb somewhere the colour is not.
|
|
90
|
+
flexShrink: 0,
|
|
91
|
+
},
|
|
92
|
+
area: {
|
|
93
|
+
width: CONTENT,
|
|
94
|
+
height: AREA_H,
|
|
95
|
+
flexShrink: 0,
|
|
96
|
+
position: 'relative',
|
|
97
|
+
cursor: 'crosshair',
|
|
98
|
+
},
|
|
99
|
+
strip: {
|
|
100
|
+
width: CONTENT,
|
|
101
|
+
height: STRIP_H,
|
|
102
|
+
flexShrink: 0,
|
|
103
|
+
position: 'relative',
|
|
104
|
+
cursor: 'pointer',
|
|
105
|
+
},
|
|
106
|
+
pane: { position: 'absolute', left: 0, top: 0, right: 0, bottom: 0 },
|
|
107
|
+
areaThumb: {
|
|
108
|
+
position: 'absolute',
|
|
109
|
+
width: THUMB,
|
|
110
|
+
height: THUMB,
|
|
111
|
+
borderRadius: THUMB / 2,
|
|
112
|
+
borderWidth: 2,
|
|
113
|
+
borderColor: 'white',
|
|
114
|
+
},
|
|
115
|
+
stripThumb: {
|
|
116
|
+
position: 'absolute',
|
|
117
|
+
top: -2,
|
|
118
|
+
width: 8,
|
|
119
|
+
height: STRIP_H + 4,
|
|
120
|
+
borderRadius: 3,
|
|
121
|
+
borderWidth: 2,
|
|
122
|
+
borderColor: 'white',
|
|
123
|
+
},
|
|
124
|
+
row: {
|
|
125
|
+
flexDirection: 'row',
|
|
126
|
+
alignItems: 'center',
|
|
127
|
+
gap: 6,
|
|
128
|
+
height: ROW_H,
|
|
129
|
+
flexShrink: 0,
|
|
130
|
+
},
|
|
131
|
+
preview: { width: ROW_H, height: ROW_H, flexShrink: 0 },
|
|
132
|
+
field: { flexGrow: 1, height: ROW_H, paddingLeft: 6, paddingRight: 6 },
|
|
133
|
+
readout: { flexGrow: 1 },
|
|
134
|
+
button: {
|
|
135
|
+
height: ROW_H,
|
|
136
|
+
paddingLeft: 8,
|
|
137
|
+
paddingRight: 8,
|
|
138
|
+
alignItems: 'center',
|
|
139
|
+
justifyContent: 'center',
|
|
140
|
+
cursor: 'pointer',
|
|
141
|
+
flexShrink: 0,
|
|
142
|
+
transition: { backgroundColor: 80 },
|
|
143
|
+
},
|
|
144
|
+
glyph: { width: 14, height: 14 },
|
|
145
|
+
swatches: { flexDirection: 'row', flexWrap: 'wrap', gap: SWATCH_GAP },
|
|
146
|
+
swatch: { width: SWATCH, height: SWATCH, cursor: 'pointer' },
|
|
147
|
+
contrast: {
|
|
148
|
+
flexDirection: 'row',
|
|
149
|
+
alignItems: 'center',
|
|
150
|
+
gap: 6,
|
|
151
|
+
height: ROW_H,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
/** The parts a picker is made of, in the order they are stacked. */
|
|
156
|
+
export type ColorPickerPart =
|
|
157
|
+
'area' | 'hue' | 'alpha' | 'fields' | 'swatches' | 'recent' | 'contrast';
|
|
158
|
+
|
|
159
|
+
/** A preset. The bare string is the common case; the object is for a preset
|
|
160
|
+
* whose name is worth reading out ("Brand primary"). */
|
|
161
|
+
export type ColorSwatch = string | { value: string; label?: string };
|
|
162
|
+
|
|
163
|
+
const swatchValue = (sw: ColorSwatch): string =>
|
|
164
|
+
typeof sw === 'string' ? sw : sw.value;
|
|
165
|
+
const swatchLabel = (sw: ColorSwatch): string =>
|
|
166
|
+
typeof sw === 'string' ? sw : (sw.label ?? sw.value);
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* What `onChange` is handed.
|
|
170
|
+
*
|
|
171
|
+
* A {@link WidgetChangeEvent} — `{ type, target: { type, name, value } }`,
|
|
172
|
+
* the shape a form library destructures — **plus** `color`. `ev.value` is the
|
|
173
|
+
* string, and `ev.color` is what it was built from, which is how an app that
|
|
174
|
+
* wants channels gets them without a second callback or an object-valued
|
|
175
|
+
* `value`. `ev.color.h` is the live hue, which the string cannot always carry:
|
|
176
|
+
* every black is hue 0 once it is written down.
|
|
177
|
+
*/
|
|
178
|
+
export interface ColorChangeEvent extends WidgetChangeEvent<string> {
|
|
179
|
+
color: ColorChannels;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function colorChangeEvent(
|
|
183
|
+
name: string | undefined,
|
|
184
|
+
value: string,
|
|
185
|
+
color: ColorChannels,
|
|
186
|
+
): ColorChangeEvent {
|
|
187
|
+
return { ...changeEvent('color', name, value), color };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface ColorPickerHandle {
|
|
191
|
+
/** Focus the first axis. */
|
|
192
|
+
focus: () => void;
|
|
193
|
+
/** Feed the picker a key it did not receive itself — what `<ColorField>`
|
|
194
|
+
* uses, the way `<DatePicker>` feeds `<Calendar>`. Answers whether the
|
|
195
|
+
* picker took it. */
|
|
196
|
+
handleKey: (ev: KeyboardEvent) => boolean;
|
|
197
|
+
readonly value: string;
|
|
198
|
+
readonly channels: ColorChannels;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface ColorPickerProps {
|
|
202
|
+
/** The colour, controlled. Any CSS colour this package can parse — which is
|
|
203
|
+
* more than the renderer can paint; see `formatColor` for what comes out. */
|
|
204
|
+
value?: string;
|
|
205
|
+
/** The colour, uncontrolled. Defaults to `#000000`. */
|
|
206
|
+
defaultValue?: string;
|
|
207
|
+
/** Every step of a drag, every arrow key, every accepted edit of the field. */
|
|
208
|
+
onChange?: (ev: ColorChangeEvent) => void;
|
|
209
|
+
/** The same event, on pointer release and on each keyboard commit — for an
|
|
210
|
+
* app whose re-render is too expensive to run per pointer step. */
|
|
211
|
+
onChangeEnd?: (ev: ColorChangeEvent) => void;
|
|
212
|
+
/** Carried on `ev.target.name`, for form libraries. */
|
|
213
|
+
name?: string;
|
|
214
|
+
/** Show the alpha strip, and emit alpha. Off by default: a picker without
|
|
215
|
+
* the strip must not start emitting `rgba()` because the value it was
|
|
216
|
+
* handed had one. */
|
|
217
|
+
alpha?: boolean;
|
|
218
|
+
/** The output spelling. `'auto'` (the default) follows the spelling the
|
|
219
|
+
* incoming value used, and hex when it used none. */
|
|
220
|
+
format?: ColorFormat | 'auto';
|
|
221
|
+
/** Presets, as a row under the panel. */
|
|
222
|
+
swatches?: readonly ColorSwatch[];
|
|
223
|
+
/** The app's recently-used colours, as a second row. Nothing is stored
|
|
224
|
+
* here — a picker that remembered would be a store. */
|
|
225
|
+
recent?: readonly ColorSwatch[];
|
|
226
|
+
/** Which parts appear, and in what order. Defaults to the parts the other
|
|
227
|
+
* props imply: the field and the hue slider, alpha when `alpha`, the
|
|
228
|
+
* fields row, and a row per non-empty swatch list. */
|
|
229
|
+
parts?: readonly ColorPickerPart[];
|
|
230
|
+
/** The eyedropper button. `true` (the default) shows it wherever core can
|
|
231
|
+
* sample the screen — `useEyedropper().supported`. A function replaces the
|
|
232
|
+
* sampler with your own, which is also how a test drives it. */
|
|
233
|
+
eyedropper?: boolean | (() => Promise<string | null>);
|
|
234
|
+
/** A colour to measure the value against: the `'contrast'` part shows the
|
|
235
|
+
* WCAG ratio and its grade. */
|
|
236
|
+
contrast?: string;
|
|
237
|
+
disabled?: boolean;
|
|
238
|
+
/** Whether the panel takes the keyboard itself. `<ColorField>` sets this
|
|
239
|
+
* false and feeds keys through the handle, because an override-redirect
|
|
240
|
+
* popup never takes focus. */
|
|
241
|
+
focusable?: boolean;
|
|
242
|
+
/** Draw the axis cursor even without the focus — the other half of
|
|
243
|
+
* `focusable={false}`. */
|
|
244
|
+
focusVisible?: boolean;
|
|
245
|
+
style?: Style | Style[];
|
|
246
|
+
'data-testname'?: string;
|
|
247
|
+
ref?: Ref<ColorPickerHandle>;
|
|
248
|
+
children?: ReactNode;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** The rows a set of parts adds up to — `<ColorField>` needs the height of
|
|
252
|
+
* the panel before the panel exists. */
|
|
253
|
+
export function colorPickerHeight(
|
|
254
|
+
parts: readonly ColorPickerPart[],
|
|
255
|
+
counts: { swatches?: number; recent?: number } = {},
|
|
256
|
+
): number {
|
|
257
|
+
const perRow = Math.floor((CONTENT + SWATCH_GAP) / (SWATCH + SWATCH_GAP));
|
|
258
|
+
const rows = (n: number): number =>
|
|
259
|
+
n
|
|
260
|
+
? Math.ceil(n / perRow) * SWATCH +
|
|
261
|
+
(Math.ceil(n / perRow) - 1) * SWATCH_GAP
|
|
262
|
+
: 0;
|
|
263
|
+
const heightOf = (part: ColorPickerPart): number => {
|
|
264
|
+
switch (part) {
|
|
265
|
+
case 'area':
|
|
266
|
+
return AREA_H;
|
|
267
|
+
case 'hue':
|
|
268
|
+
case 'alpha':
|
|
269
|
+
return STRIP_H;
|
|
270
|
+
case 'fields':
|
|
271
|
+
case 'contrast':
|
|
272
|
+
return ROW_H;
|
|
273
|
+
case 'swatches':
|
|
274
|
+
return rows(counts.swatches ?? 0);
|
|
275
|
+
case 'recent':
|
|
276
|
+
return rows(counts.recent ?? 0);
|
|
277
|
+
default:
|
|
278
|
+
return 0;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
const heights = parts.map(heightOf).filter((h) => h > 0);
|
|
282
|
+
return (
|
|
283
|
+
PAD * 2 +
|
|
284
|
+
heights.reduce((sum, h) => sum + h, 0) +
|
|
285
|
+
Math.max(0, heights.length - 1) * GAP
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const clamp01 = (n: number): number => (n < 0 ? 0 : n > 1 ? 1 : n);
|
|
290
|
+
|
|
291
|
+
/** The checkerboard under anything translucent. Two greys rather than a
|
|
292
|
+
* theme colour: it is a *hole*, and a hole looks the same on every palette. */
|
|
293
|
+
function drawChecker(ctx: any, width: number, height: number): void {
|
|
294
|
+
ctx.fillStyle = '#ffffff';
|
|
295
|
+
ctx.fillRect(0, 0, width, height);
|
|
296
|
+
ctx.fillStyle = '#c8c8c8';
|
|
297
|
+
for (let y = 0; y < height; y += CHECKER) {
|
|
298
|
+
for (let x = 0; x < width; x += CHECKER) {
|
|
299
|
+
if (((x / CHECKER) & 1) === ((y / CHECKER) & 1)) continue;
|
|
300
|
+
ctx.fillRect(
|
|
301
|
+
x,
|
|
302
|
+
y,
|
|
303
|
+
Math.min(CHECKER, width - x),
|
|
304
|
+
Math.min(CHECKER, height - y),
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* The dropper glyph: the bulb at the top right, the stem running down to the
|
|
312
|
+
* left, and the tip it draws with. Three shapes rather than one clever path,
|
|
313
|
+
* because at 14 pixels a pipette reads only if the bulb and the tip are both
|
|
314
|
+
* solid — the first draft was a single stroke and looked like a slash.
|
|
315
|
+
*/
|
|
316
|
+
function EyedropperGlyph({ color }: { color: string }): ReactElement {
|
|
317
|
+
return hx('canvas', {
|
|
318
|
+
style: s.glyph,
|
|
319
|
+
cacheKey: `eyedropper:${color}`,
|
|
320
|
+
onDraw: (ctx, { width, height }) => {
|
|
321
|
+
ctx.fillStyle = color;
|
|
322
|
+
ctx.strokeStyle = color;
|
|
323
|
+
// the bulb
|
|
324
|
+
ctx.beginPath();
|
|
325
|
+
ctx.arc(width - 3.5, 3.5, 3, 0, Math.PI * 2);
|
|
326
|
+
ctx.fill();
|
|
327
|
+
// the stem
|
|
328
|
+
ctx.lineWidth = 2;
|
|
329
|
+
ctx.beginPath();
|
|
330
|
+
ctx.moveTo(width - 5, 5);
|
|
331
|
+
ctx.lineTo(4.5, height - 4.5);
|
|
332
|
+
ctx.stroke();
|
|
333
|
+
// the tip, pointing at what it will sample
|
|
334
|
+
ctx.beginPath();
|
|
335
|
+
ctx.moveTo(1, height - 1);
|
|
336
|
+
ctx.lineTo(5.5, height - 2.5);
|
|
337
|
+
ctx.lineTo(2.5, height - 5.5);
|
|
338
|
+
ctx.closePath();
|
|
339
|
+
ctx.fill();
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* `<ColorPicker value onChange>` — the colour panel.
|
|
346
|
+
*
|
|
347
|
+
* <ColorPicker value={accent} onChange={(ev) => setAccent(ev.value)} />
|
|
348
|
+
* <ColorPicker … alpha swatches={brand.colors} />
|
|
349
|
+
* <ColorPicker … parts={['swatches']} /> // the palette-only shape
|
|
350
|
+
*
|
|
351
|
+
* The value is a **CSS colour string**, the way a `<Calendar>`'s day is a
|
|
352
|
+
* `'YYYY-MM-DD'` string: it drops straight into `backgroundColor`, survives
|
|
353
|
+
* JSON, and needs no constructor. What it cannot carry is the hue behind a
|
|
354
|
+
* black or a grey, so the picker holds HSVA of its own and adopts the `value`
|
|
355
|
+
* prop only when that prop is not the string it last emitted. Drag the
|
|
356
|
+
* brightness to zero and back and the hue is still where it was.
|
|
357
|
+
*/
|
|
358
|
+
export function ColorPicker(props: ColorPickerProps): ReactElement {
|
|
359
|
+
const {
|
|
360
|
+
value,
|
|
361
|
+
defaultValue,
|
|
362
|
+
onChange,
|
|
363
|
+
onChangeEnd,
|
|
364
|
+
name,
|
|
365
|
+
alpha = false,
|
|
366
|
+
format = 'auto',
|
|
367
|
+
swatches,
|
|
368
|
+
recent,
|
|
369
|
+
parts,
|
|
370
|
+
eyedropper = true,
|
|
371
|
+
contrast,
|
|
372
|
+
disabled = false,
|
|
373
|
+
focusable = true,
|
|
374
|
+
focusVisible,
|
|
375
|
+
style,
|
|
376
|
+
children,
|
|
377
|
+
ref,
|
|
378
|
+
} = props;
|
|
379
|
+
|
|
380
|
+
const theme = useTheme();
|
|
381
|
+
const [model, setModel] = useState<ColorChannels>(
|
|
382
|
+
() =>
|
|
383
|
+
parseColor(value ?? defaultValue ?? '') ?? channelsFromHsv(0, 0, 0, 1),
|
|
384
|
+
);
|
|
385
|
+
// What the last emitted string was, so that an app echoing it back is a
|
|
386
|
+
// no-op rather than a re-parse that loses the hue.
|
|
387
|
+
const emitted = useRef<string | null>(null);
|
|
388
|
+
// The spelling `format="auto"` follows: whatever the last string that came
|
|
389
|
+
// *in* was written in.
|
|
390
|
+
const [sourceFormat, setSourceFormat] = useState<ColorFormat>(
|
|
391
|
+
() => formatOf(value ?? defaultValue ?? '') ?? 'hex',
|
|
392
|
+
);
|
|
393
|
+
const [prevValue, setPrevValue] = useState(value);
|
|
394
|
+
const [dragging, setDragging] = useState<'area' | 'hue' | 'alpha' | null>(
|
|
395
|
+
null,
|
|
396
|
+
);
|
|
397
|
+
const [active, setActive] = useState<'area' | 'hue' | 'alpha'>('area');
|
|
398
|
+
const [focused, setFocused] = useState(false);
|
|
399
|
+
const [typed, setTyped] = useState<string | null>(null);
|
|
400
|
+
const [textModel, setTextModel] = useState<ColorFormat>('hex');
|
|
401
|
+
const areaRef = useRef<DrawnNode | null>(null);
|
|
402
|
+
const hueRef = useRef<DrawnNode | null>(null);
|
|
403
|
+
const alphaRef = useRef<DrawnNode | null>(null);
|
|
404
|
+
|
|
405
|
+
// Controlled reconciliation, at render — React's own "adjusting state when
|
|
406
|
+
// a prop changes" pattern. The hue of the model survives a value that has
|
|
407
|
+
// none of its own, which is what makes dragging through black work.
|
|
408
|
+
if (value !== undefined && value !== prevValue) {
|
|
409
|
+
setPrevValue(value);
|
|
410
|
+
if (value !== emitted.current) {
|
|
411
|
+
const parsed = parseColor(value);
|
|
412
|
+
if (parsed) {
|
|
413
|
+
setModel(
|
|
414
|
+
channelsFromRgb(parsed.r, parsed.g, parsed.b, parsed.a, model.h),
|
|
415
|
+
);
|
|
416
|
+
setSourceFormat(formatOf(value) ?? sourceFormat);
|
|
417
|
+
setTyped(null);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const outputFormat: ColorFormat = format === 'auto' ? sourceFormat : format;
|
|
423
|
+
const text = formatColor(model, outputFormat, alpha);
|
|
424
|
+
const dropper = useEyedropper();
|
|
425
|
+
|
|
426
|
+
const emit = (
|
|
427
|
+
next: ColorChannels,
|
|
428
|
+
done: boolean,
|
|
429
|
+
// The spelling to emit in, when the caller already knows it: `setState`
|
|
430
|
+
// does not land until the next render, so a swatch or a typed value that
|
|
431
|
+
// brings its own format has to hand it over rather than set it and read
|
|
432
|
+
// it back in the same handler.
|
|
433
|
+
spelling: ColorFormat = outputFormat,
|
|
434
|
+
): void => {
|
|
435
|
+
const out = formatColor(next, spelling, alpha);
|
|
436
|
+
emitted.current = out;
|
|
437
|
+
setModel(next);
|
|
438
|
+
setTyped(null);
|
|
439
|
+
const ev = colorChangeEvent(name, out, next);
|
|
440
|
+
onChange?.(ev);
|
|
441
|
+
if (done) onChangeEnd?.(ev);
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
/** Commit whatever the current model is — the release of a drag, and the
|
|
445
|
+
* end of a keyboard step. */
|
|
446
|
+
const commit = (next: ColorChannels): void => emit(next, true);
|
|
447
|
+
|
|
448
|
+
/** Take a colour from somewhere that is not this widget — the screen, or a
|
|
449
|
+
* swatch. The hue comes along when the new colour has none of its own, and
|
|
450
|
+
* the alpha only when there is a strip to show it on. */
|
|
451
|
+
const adopt = (colour: string): void => {
|
|
452
|
+
const parsed = parseColor(colour);
|
|
453
|
+
if (!parsed) return;
|
|
454
|
+
const spelling = formatOf(colour) ?? sourceFormat;
|
|
455
|
+
setSourceFormat(spelling);
|
|
456
|
+
emit(
|
|
457
|
+
channelsFromRgb(
|
|
458
|
+
parsed.r,
|
|
459
|
+
parsed.g,
|
|
460
|
+
parsed.b,
|
|
461
|
+
alpha ? parsed.a : 1,
|
|
462
|
+
model.h,
|
|
463
|
+
),
|
|
464
|
+
true,
|
|
465
|
+
format === 'auto' ? spelling : outputFormat,
|
|
466
|
+
);
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
// `eyedropper` is a switch and a seam at once: `true` takes core's sampler
|
|
470
|
+
// — `useEyedropper()` answers `supported: false` where there is none, which
|
|
471
|
+
// is the button's existence — and a function replaces it, which is both the
|
|
472
|
+
// kiosk case and how a test drives a pick without a server.
|
|
473
|
+
const ownDropper = typeof eyedropper === 'function' ? eyedropper : null;
|
|
474
|
+
const showDropper =
|
|
475
|
+
!disabled &&
|
|
476
|
+
(ownDropper !== null || (eyedropper !== false && dropper.supported));
|
|
477
|
+
const pickFromScreen = (): void => {
|
|
478
|
+
const pick = ownDropper ?? dropper.pick;
|
|
479
|
+
void Promise.resolve(pick()).then((hex) => {
|
|
480
|
+
// null is a cancel, and a cancel leaves the colour alone.
|
|
481
|
+
if (hex) adopt(hex);
|
|
482
|
+
});
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
const setHsv = (h: number, sat: number, v: number, done = false): void =>
|
|
486
|
+
emit(channelsFromHsv(h, sat, v, model.a), done);
|
|
487
|
+
|
|
488
|
+
// --- pointer ------------------------------------------------------------
|
|
489
|
+
|
|
490
|
+
const fractionIn = (
|
|
491
|
+
node: DrawnNode | null,
|
|
492
|
+
ev: MouseEvent,
|
|
493
|
+
): { x: number; y: number } | null => {
|
|
494
|
+
const box = node?.abs;
|
|
495
|
+
if (!box?.width || !box.height) return null;
|
|
496
|
+
return {
|
|
497
|
+
x: clamp01((ev.x - box.x) / box.width),
|
|
498
|
+
y: clamp01((ev.y - box.y) / box.height),
|
|
499
|
+
};
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
const areaTo = (ev: MouseEvent, done: boolean): void => {
|
|
503
|
+
const at = fractionIn(areaRef.current, ev);
|
|
504
|
+
if (at) setHsv(model.h, at.x, 1 - at.y, done);
|
|
505
|
+
};
|
|
506
|
+
const hueTo = (ev: MouseEvent, done: boolean): void => {
|
|
507
|
+
const at = fractionIn(hueRef.current, ev);
|
|
508
|
+
if (at) setHsv(at.x * 360, model.s, model.v, done);
|
|
509
|
+
};
|
|
510
|
+
const alphaTo = (ev: MouseEvent, done: boolean): void => {
|
|
511
|
+
const at = fractionIn(alphaRef.current, ev);
|
|
512
|
+
if (at) emit(channelsFromHsv(model.h, model.s, model.v, at.x), done);
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const track = (
|
|
516
|
+
axis: 'area' | 'hue' | 'alpha',
|
|
517
|
+
to: (ev: MouseEvent, done: boolean) => void,
|
|
518
|
+
): Record<string, (ev: MouseEvent) => void> =>
|
|
519
|
+
disabled
|
|
520
|
+
? {}
|
|
521
|
+
: {
|
|
522
|
+
onMouseDown: (ev: MouseEvent) => {
|
|
523
|
+
ev.capturePointer();
|
|
524
|
+
setDragging(axis);
|
|
525
|
+
setActive(axis);
|
|
526
|
+
to(ev, false);
|
|
527
|
+
},
|
|
528
|
+
onMouseMove: (ev: MouseEvent) => {
|
|
529
|
+
if (dragging === axis) to(ev, false);
|
|
530
|
+
},
|
|
531
|
+
onMouseUp: (ev: MouseEvent) => {
|
|
532
|
+
if (dragging !== axis) return;
|
|
533
|
+
setDragging(null);
|
|
534
|
+
to(ev, true);
|
|
535
|
+
},
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// --- keyboard -----------------------------------------------------------
|
|
539
|
+
|
|
540
|
+
const axes = (): ('area' | 'hue' | 'alpha')[] =>
|
|
541
|
+
(['area', 'hue', 'alpha'] as const).filter((part) => shown.includes(part));
|
|
542
|
+
|
|
543
|
+
const step = (ev: KeyboardEvent, coarse: number, fine: number): number =>
|
|
544
|
+
ev.shiftKey ? coarse : fine;
|
|
545
|
+
|
|
546
|
+
const handleKey = (ev: KeyboardEvent): boolean => {
|
|
547
|
+
if (disabled) return false;
|
|
548
|
+
const axis = axes().includes(active) ? active : (axes()[0] ?? 'area');
|
|
549
|
+
const dx = step(ev, 0.1, 0.01);
|
|
550
|
+
switch (ev.keysym) {
|
|
551
|
+
case XK_LEFT:
|
|
552
|
+
case XK_RIGHT: {
|
|
553
|
+
const dir = ev.keysym === XK_LEFT ? -1 : 1;
|
|
554
|
+
if (axis === 'hue')
|
|
555
|
+
setHsv(model.h + dir * step(ev, 10, 1), model.s, model.v, true);
|
|
556
|
+
else if (axis === 'alpha')
|
|
557
|
+
commit(
|
|
558
|
+
channelsFromHsv(model.h, model.s, model.v, model.a + dir * dx),
|
|
559
|
+
);
|
|
560
|
+
else setHsv(model.h, model.s + dir * dx, model.v, true);
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
case XK_UP:
|
|
564
|
+
case XK_DOWN: {
|
|
565
|
+
if (axis !== 'area') return false;
|
|
566
|
+
const dir = ev.keysym === XK_UP ? 1 : -1;
|
|
567
|
+
setHsv(model.h, model.s, model.v + dir * dx, true);
|
|
568
|
+
return true;
|
|
569
|
+
}
|
|
570
|
+
case XK_HOME:
|
|
571
|
+
case XK_END: {
|
|
572
|
+
const end = ev.keysym === XK_END;
|
|
573
|
+
if (axis === 'hue') setHsv(end ? 360 : 0, model.s, model.v, true);
|
|
574
|
+
else if (axis === 'alpha')
|
|
575
|
+
commit(channelsFromHsv(model.h, model.s, model.v, end ? 1 : 0));
|
|
576
|
+
else setHsv(model.h, end ? 1 : 0, model.v, true);
|
|
577
|
+
return true;
|
|
578
|
+
}
|
|
579
|
+
case XK_PAGE_UP:
|
|
580
|
+
case XK_PAGE_DOWN: {
|
|
581
|
+
if (axis !== 'area') return false;
|
|
582
|
+
setHsv(model.h, model.s, ev.keysym === XK_PAGE_UP ? 1 : 0, true);
|
|
583
|
+
return true;
|
|
584
|
+
}
|
|
585
|
+
case XK_TAB: {
|
|
586
|
+
// Only ours when the panel does not own the focus: a picker on a
|
|
587
|
+
// popup is fed its keys by the trigger, and without this its hue
|
|
588
|
+
// slider would be unreachable from the keyboard. Answering `false` at
|
|
589
|
+
// the ends is what lets Tab leave the picker.
|
|
590
|
+
if (focusable) return false;
|
|
591
|
+
const list = axes();
|
|
592
|
+
const at = list.indexOf(axis);
|
|
593
|
+
const next = at + (ev.shiftKey ? -1 : 1);
|
|
594
|
+
if (next < 0 || next >= list.length) return false;
|
|
595
|
+
setActive(list[next]);
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
598
|
+
default:
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
useImperativeHandle(ref, () => ({
|
|
604
|
+
focus: () => {
|
|
605
|
+
areaRef.current?.focus() ?? hueRef.current?.focus();
|
|
606
|
+
},
|
|
607
|
+
handleKey,
|
|
608
|
+
get value() {
|
|
609
|
+
return text;
|
|
610
|
+
},
|
|
611
|
+
get channels() {
|
|
612
|
+
return model;
|
|
613
|
+
},
|
|
614
|
+
}));
|
|
615
|
+
|
|
616
|
+
// --- the parts ----------------------------------------------------------
|
|
617
|
+
|
|
618
|
+
const shown: ColorPickerPart[] =
|
|
619
|
+
parts !== undefined
|
|
620
|
+
? [...parts]
|
|
621
|
+
: [
|
|
622
|
+
'area',
|
|
623
|
+
'hue',
|
|
624
|
+
...(alpha ? (['alpha'] as const) : []),
|
|
625
|
+
'fields',
|
|
626
|
+
...(swatches?.length ? (['swatches'] as const) : []),
|
|
627
|
+
...(recent?.length ? (['recent'] as const) : []),
|
|
628
|
+
...(contrast ? (['contrast'] as const) : []),
|
|
629
|
+
];
|
|
630
|
+
|
|
631
|
+
const cursorShown = focusVisible ?? focused;
|
|
632
|
+
const hue = opaqueHex(channelsFromHsv(model.h, 1, 1));
|
|
633
|
+
const ink = disabled ? theme.textMuted : theme.text;
|
|
634
|
+
|
|
635
|
+
const axisProps = (
|
|
636
|
+
axis: 'area' | 'hue' | 'alpha',
|
|
637
|
+
label: string,
|
|
638
|
+
valueText: string,
|
|
639
|
+
now: number,
|
|
640
|
+
max: number,
|
|
641
|
+
): Record<string, unknown> => ({
|
|
642
|
+
role: 'slider',
|
|
643
|
+
'aria-label': label,
|
|
644
|
+
// The number alone means nothing read out loud, so every axis says what
|
|
645
|
+
// it is in words as well — the one part of React Aria's colour grammar
|
|
646
|
+
// that is pure gain.
|
|
647
|
+
'aria-valuetext': valueText,
|
|
648
|
+
'aria-valuenow': Math.round(now),
|
|
649
|
+
'aria-valuemin': 0,
|
|
650
|
+
'aria-valuemax': max,
|
|
651
|
+
'aria-disabled': disabled || undefined,
|
|
652
|
+
focusable: focusable && !disabled,
|
|
653
|
+
onFocus: () => {
|
|
654
|
+
setFocused(true);
|
|
655
|
+
setActive(axis);
|
|
656
|
+
},
|
|
657
|
+
onBlur: () => setFocused(false),
|
|
658
|
+
onKeyDown: focusable ? handleKey : undefined,
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
const renderArea = (): ReactElement =>
|
|
662
|
+
hx(
|
|
663
|
+
'box',
|
|
664
|
+
{
|
|
665
|
+
key: 'area',
|
|
666
|
+
ref: areaRef,
|
|
667
|
+
...axisProps(
|
|
668
|
+
'area',
|
|
669
|
+
'Saturation and brightness',
|
|
670
|
+
`saturation ${Math.round(model.s * 100)}%, brightness ${Math.round(model.v * 100)}%`,
|
|
671
|
+
model.s * 100,
|
|
672
|
+
100,
|
|
673
|
+
),
|
|
674
|
+
style: [
|
|
675
|
+
s.area,
|
|
676
|
+
{
|
|
677
|
+
borderWidth: theme.borderWidth,
|
|
678
|
+
borderColor:
|
|
679
|
+
cursorShown && active === 'area'
|
|
680
|
+
? theme.borderFocus
|
|
681
|
+
: theme.border,
|
|
682
|
+
},
|
|
683
|
+
],
|
|
684
|
+
...track('area', areaTo),
|
|
685
|
+
},
|
|
686
|
+
hx('canvas', {
|
|
687
|
+
style: s.pane,
|
|
688
|
+
// Everything the drawing reads: the hue, and the size, which is a
|
|
689
|
+
// constant here precisely so this key can name it.
|
|
690
|
+
cacheKey: `sv:${Math.round(model.h)}:${CONTENT}x${AREA_H}`,
|
|
691
|
+
onDraw: (ctx, { width, height }) => {
|
|
692
|
+
ctx.fillStyle = hue;
|
|
693
|
+
ctx.fillRect(0, 0, width, height);
|
|
694
|
+
// Legacy comma spelling in the stops, for the same reason
|
|
695
|
+
// `formatColor` emits it: it is what ntk's parser understands.
|
|
696
|
+
const white = ctx.createLinearGradient(0, 0, width, 0);
|
|
697
|
+
white.addColorStop(0, 'rgb(255, 255, 255)');
|
|
698
|
+
white.addColorStop(1, 'rgba(255, 255, 255, 0)');
|
|
699
|
+
ctx.fillStyle = white;
|
|
700
|
+
ctx.fillRect(0, 0, width, height);
|
|
701
|
+
const black = ctx.createLinearGradient(0, 0, 0, height);
|
|
702
|
+
black.addColorStop(0, 'rgba(0, 0, 0, 0)');
|
|
703
|
+
black.addColorStop(1, 'rgb(0, 0, 0)');
|
|
704
|
+
ctx.fillStyle = black;
|
|
705
|
+
ctx.fillRect(0, 0, width, height);
|
|
706
|
+
},
|
|
707
|
+
}),
|
|
708
|
+
hx('box', {
|
|
709
|
+
style: [
|
|
710
|
+
s.areaThumb,
|
|
711
|
+
{
|
|
712
|
+
left: model.s * CONTENT - THUMB / 2,
|
|
713
|
+
top: (1 - model.v) * AREA_H - THUMB / 2,
|
|
714
|
+
backgroundColor: opaqueHex(model),
|
|
715
|
+
},
|
|
716
|
+
],
|
|
717
|
+
}),
|
|
718
|
+
);
|
|
719
|
+
|
|
720
|
+
const renderHue = (): ReactElement =>
|
|
721
|
+
hx(
|
|
722
|
+
'box',
|
|
723
|
+
{
|
|
724
|
+
key: 'hue',
|
|
725
|
+
ref: hueRef,
|
|
726
|
+
...axisProps(
|
|
727
|
+
'hue',
|
|
728
|
+
'Hue',
|
|
729
|
+
`hue ${Math.round(model.h)} degrees`,
|
|
730
|
+
model.h,
|
|
731
|
+
360,
|
|
732
|
+
),
|
|
733
|
+
style: [
|
|
734
|
+
s.strip,
|
|
735
|
+
{
|
|
736
|
+
borderWidth: theme.borderWidth,
|
|
737
|
+
borderColor:
|
|
738
|
+
cursorShown && active === 'hue'
|
|
739
|
+
? theme.borderFocus
|
|
740
|
+
: theme.border,
|
|
741
|
+
},
|
|
742
|
+
],
|
|
743
|
+
...track('hue', hueTo),
|
|
744
|
+
},
|
|
745
|
+
hx('canvas', {
|
|
746
|
+
style: s.pane,
|
|
747
|
+
cacheKey: `hue:${CONTENT}x${STRIP_H}`,
|
|
748
|
+
onDraw: (ctx, { width, height }) => {
|
|
749
|
+
const ramp = ctx.createLinearGradient(0, 0, width, 0);
|
|
750
|
+
for (let stop = 0; stop <= 6; stop += 1) {
|
|
751
|
+
ramp.addColorStop(
|
|
752
|
+
stop / 6,
|
|
753
|
+
opaqueHex(channelsFromHsv(stop * 60, 1, 1)),
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
ctx.fillStyle = ramp;
|
|
757
|
+
ctx.fillRect(0, 0, width, height);
|
|
758
|
+
},
|
|
759
|
+
}),
|
|
760
|
+
hx('box', {
|
|
761
|
+
style: [
|
|
762
|
+
s.stripThumb,
|
|
763
|
+
{ left: (model.h / 360) * CONTENT - 4, backgroundColor: hue },
|
|
764
|
+
],
|
|
765
|
+
}),
|
|
766
|
+
);
|
|
767
|
+
|
|
768
|
+
const renderAlpha = (): ReactElement =>
|
|
769
|
+
hx(
|
|
770
|
+
'box',
|
|
771
|
+
{
|
|
772
|
+
key: 'alpha',
|
|
773
|
+
ref: alphaRef,
|
|
774
|
+
...axisProps(
|
|
775
|
+
'alpha',
|
|
776
|
+
'Opacity',
|
|
777
|
+
`opacity ${Math.round(model.a * 100)}%`,
|
|
778
|
+
model.a * 100,
|
|
779
|
+
100,
|
|
780
|
+
),
|
|
781
|
+
style: [
|
|
782
|
+
s.strip,
|
|
783
|
+
{
|
|
784
|
+
borderWidth: theme.borderWidth,
|
|
785
|
+
borderColor:
|
|
786
|
+
cursorShown && active === 'alpha'
|
|
787
|
+
? theme.borderFocus
|
|
788
|
+
: theme.border,
|
|
789
|
+
},
|
|
790
|
+
],
|
|
791
|
+
...track('alpha', alphaTo),
|
|
792
|
+
},
|
|
793
|
+
hx('canvas', {
|
|
794
|
+
style: s.pane,
|
|
795
|
+
cacheKey: `alpha:${opaqueHex(model)}:${CONTENT}x${STRIP_H}`,
|
|
796
|
+
onDraw: (ctx, { width, height }) => {
|
|
797
|
+
drawChecker(ctx, width, height);
|
|
798
|
+
const ramp = ctx.createLinearGradient(0, 0, width, 0);
|
|
799
|
+
const { r, g, b } = model;
|
|
800
|
+
ramp.addColorStop(0, `rgba(${r}, ${g}, ${b}, 0)`);
|
|
801
|
+
ramp.addColorStop(1, `rgb(${r}, ${g}, ${b})`);
|
|
802
|
+
ctx.fillStyle = ramp;
|
|
803
|
+
ctx.fillRect(0, 0, width, height);
|
|
804
|
+
},
|
|
805
|
+
}),
|
|
806
|
+
hx('box', {
|
|
807
|
+
style: [
|
|
808
|
+
s.stripThumb,
|
|
809
|
+
{ left: model.a * CONTENT - 4, backgroundColor: opaqueHex(model) },
|
|
810
|
+
],
|
|
811
|
+
}),
|
|
812
|
+
);
|
|
813
|
+
|
|
814
|
+
/** A colour chip: the checkerboard, then the colour over it. Used for the
|
|
815
|
+
* preview and for every swatch, so a translucent preset reads as one. */
|
|
816
|
+
const chip = (
|
|
817
|
+
// `where` is part of the cache key, not decoration: every chip is the
|
|
818
|
+
// same drawing at a different size, and a key that named only the colour
|
|
819
|
+
// would let a 16px contrast chip composite a 26px preview's surface. The
|
|
820
|
+
// sizes are constants per call site, so the name is enough to separate
|
|
821
|
+
// them — this is the "a key that leaves an input out shows stale pixels"
|
|
822
|
+
// trap, found by looking at a real window.
|
|
823
|
+
where: 'preview' | 'swatch' | 'contrast',
|
|
824
|
+
colour: ColorChannels,
|
|
825
|
+
style: Style | Style[],
|
|
826
|
+
key?: string,
|
|
827
|
+
): ReactElement =>
|
|
828
|
+
hx('canvas', {
|
|
829
|
+
key,
|
|
830
|
+
style,
|
|
831
|
+
cacheKey: `chip:${where}:${formatColor(colour, 'hex', true)}`,
|
|
832
|
+
onDraw: (ctx, { width, height }) => {
|
|
833
|
+
if (colour.a < 1) drawChecker(ctx, width, height);
|
|
834
|
+
const { r, g, b, a } = colour;
|
|
835
|
+
ctx.fillStyle =
|
|
836
|
+
a < 1 ? `rgba(${r}, ${g}, ${b}, ${a})` : opaqueHex(colour);
|
|
837
|
+
ctx.fillRect(0, 0, width, height);
|
|
838
|
+
},
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
/** What the field accepted, or a revert. A typed value that is not a colour
|
|
842
|
+
* is not an error state — the field simply goes back to the model, which
|
|
843
|
+
* is what every other picker does and what an escape key would have. */
|
|
844
|
+
const applyText = (raw: string): void => {
|
|
845
|
+
if (parseColor(raw)) adopt(raw);
|
|
846
|
+
else setTyped(null);
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
const modelText = (): string => {
|
|
850
|
+
if (textModel === 'hex') return formatColor(model, 'hex', alpha);
|
|
851
|
+
if (textModel === 'rgb') return formatColor(model, 'rgb', alpha);
|
|
852
|
+
return formatColor(model, 'hsl', alpha);
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
const renderFields = (): ReactElement =>
|
|
856
|
+
hx(
|
|
857
|
+
'box',
|
|
858
|
+
{ key: 'fields', style: s.row },
|
|
859
|
+
chip('preview', model, [
|
|
860
|
+
s.preview,
|
|
861
|
+
{ borderWidth: theme.borderWidth, borderColor: theme.border },
|
|
862
|
+
]),
|
|
863
|
+
// An override-redirect popup never takes the focus, so a `<textinput>`
|
|
864
|
+
// inside one could never be typed into — `<ColorField>` renders the
|
|
865
|
+
// value as a readout instead, and its own trigger is where a typed
|
|
866
|
+
// colour goes.
|
|
867
|
+
focusable
|
|
868
|
+
? hx('textinput', {
|
|
869
|
+
value: typed ?? modelText(),
|
|
870
|
+
'aria-label': 'Colour value',
|
|
871
|
+
disabled: disabled || undefined,
|
|
872
|
+
style: [
|
|
873
|
+
s.field,
|
|
874
|
+
{
|
|
875
|
+
borderWidth: theme.borderWidth,
|
|
876
|
+
borderRadius: theme.radius,
|
|
877
|
+
borderColor: theme.border,
|
|
878
|
+
backgroundColor: theme.surface,
|
|
879
|
+
fontFamily: theme.monoFamily,
|
|
880
|
+
},
|
|
881
|
+
],
|
|
882
|
+
onChange: (ev: ChangeEvent<TextInputNode>) => setTyped(ev.value),
|
|
883
|
+
onSubmit: () => applyText(typed ?? ''),
|
|
884
|
+
onBlur: () => (typed === null ? undefined : applyText(typed)),
|
|
885
|
+
onKeyDown: (ev: KeyboardEvent) => {
|
|
886
|
+
if (ev.keysym === XK_ESCAPE) setTyped(null);
|
|
887
|
+
else if (ev.keysym === XK_RETURN) applyText(typed ?? '');
|
|
888
|
+
},
|
|
889
|
+
})
|
|
890
|
+
: hx(
|
|
891
|
+
'text',
|
|
892
|
+
{
|
|
893
|
+
style: [s.readout, { color: ink, fontFamily: theme.monoFamily }],
|
|
894
|
+
},
|
|
895
|
+
modelText(),
|
|
896
|
+
),
|
|
897
|
+
hx(
|
|
898
|
+
'box',
|
|
899
|
+
{
|
|
900
|
+
role: 'button',
|
|
901
|
+
'aria-label': `Value as ${textModel.toUpperCase()} — press to change`,
|
|
902
|
+
focusable: focusable && !disabled,
|
|
903
|
+
style: [
|
|
904
|
+
s.button,
|
|
905
|
+
{
|
|
906
|
+
borderRadius: theme.radius,
|
|
907
|
+
':hover': { backgroundColor: theme.surfaceHover },
|
|
908
|
+
':active': { backgroundColor: theme.surfaceActive },
|
|
909
|
+
},
|
|
910
|
+
],
|
|
911
|
+
onClick: disabled
|
|
912
|
+
? undefined
|
|
913
|
+
: () => {
|
|
914
|
+
setTyped(null);
|
|
915
|
+
setTextModel(
|
|
916
|
+
textModel === 'hex'
|
|
917
|
+
? 'rgb'
|
|
918
|
+
: textModel === 'rgb'
|
|
919
|
+
? 'hsl'
|
|
920
|
+
: 'hex',
|
|
921
|
+
);
|
|
922
|
+
},
|
|
923
|
+
},
|
|
924
|
+
hx(
|
|
925
|
+
'text',
|
|
926
|
+
{ style: { color: ink, fontSize: 11 } },
|
|
927
|
+
textModel.toUpperCase(),
|
|
928
|
+
),
|
|
929
|
+
),
|
|
930
|
+
showDropper &&
|
|
931
|
+
hx(
|
|
932
|
+
'box',
|
|
933
|
+
{
|
|
934
|
+
role: 'button',
|
|
935
|
+
'aria-label': 'Pick a colour from the screen',
|
|
936
|
+
focusable: focusable && !disabled,
|
|
937
|
+
disabled: disabled || dropper.picking || undefined,
|
|
938
|
+
style: [
|
|
939
|
+
s.button,
|
|
940
|
+
{
|
|
941
|
+
borderRadius: theme.radius,
|
|
942
|
+
':hover': { backgroundColor: theme.surfaceHover },
|
|
943
|
+
':active': { backgroundColor: theme.surfaceActive },
|
|
944
|
+
},
|
|
945
|
+
],
|
|
946
|
+
onClick: disabled || dropper.picking ? undefined : pickFromScreen,
|
|
947
|
+
},
|
|
948
|
+
React.createElement(EyedropperGlyph, { color: ink }),
|
|
949
|
+
),
|
|
950
|
+
);
|
|
951
|
+
|
|
952
|
+
const renderSwatches = (
|
|
953
|
+
key: 'swatches' | 'recent',
|
|
954
|
+
list: readonly ColorSwatch[],
|
|
955
|
+
): ReactElement =>
|
|
956
|
+
hx(
|
|
957
|
+
'box',
|
|
958
|
+
{
|
|
959
|
+
key,
|
|
960
|
+
role: 'group',
|
|
961
|
+
'aria-label': key === 'recent' ? 'Recent colours' : 'Swatches',
|
|
962
|
+
style: s.swatches,
|
|
963
|
+
},
|
|
964
|
+
...list.map((sw, i) => {
|
|
965
|
+
const parsed = parseColor(swatchValue(sw));
|
|
966
|
+
const chosen =
|
|
967
|
+
parsed &&
|
|
968
|
+
formatColor(parsed, 'hex', true) === formatColor(model, 'hex', true);
|
|
969
|
+
return hx(
|
|
970
|
+
'box',
|
|
971
|
+
{
|
|
972
|
+
key: `${key}:${i}`,
|
|
973
|
+
role: 'button',
|
|
974
|
+
'aria-label': swatchLabel(sw),
|
|
975
|
+
'aria-pressed': Boolean(chosen),
|
|
976
|
+
focusable: focusable && !disabled,
|
|
977
|
+
style: [
|
|
978
|
+
s.swatch,
|
|
979
|
+
{
|
|
980
|
+
borderRadius: theme.radius,
|
|
981
|
+
borderWidth: chosen ? 2 : theme.borderWidth,
|
|
982
|
+
borderColor: chosen ? theme.accent : theme.border,
|
|
983
|
+
},
|
|
984
|
+
],
|
|
985
|
+
onClick: disabled ? undefined : () => adopt(swatchValue(sw)),
|
|
986
|
+
onKeyDown: (ev: KeyboardEvent) => {
|
|
987
|
+
if (disabled) return;
|
|
988
|
+
if (ev.keysym === XK_RETURN || ev.codepoint === 32)
|
|
989
|
+
adopt(swatchValue(sw));
|
|
990
|
+
},
|
|
991
|
+
},
|
|
992
|
+
parsed ? chip('swatch', parsed, s.pane) : null,
|
|
993
|
+
);
|
|
994
|
+
}),
|
|
995
|
+
);
|
|
996
|
+
|
|
997
|
+
const renderContrast = (): ReactElement | null => {
|
|
998
|
+
if (!contrast) return null;
|
|
999
|
+
const ratio = contrastRatio(model, contrast);
|
|
1000
|
+
if (ratio === null) return null;
|
|
1001
|
+
const grade = contrastGrade(ratio);
|
|
1002
|
+
const colour =
|
|
1003
|
+
grade === 'fail'
|
|
1004
|
+
? theme.danger
|
|
1005
|
+
: grade === 'AA'
|
|
1006
|
+
? theme.warning
|
|
1007
|
+
: theme.success;
|
|
1008
|
+
return hx(
|
|
1009
|
+
'box',
|
|
1010
|
+
{ key: 'contrast', style: s.contrast },
|
|
1011
|
+
chip('contrast', parseColor(contrast) ?? model, [
|
|
1012
|
+
{
|
|
1013
|
+
width: 16,
|
|
1014
|
+
height: 16,
|
|
1015
|
+
borderWidth: theme.borderWidth,
|
|
1016
|
+
borderColor: theme.border,
|
|
1017
|
+
},
|
|
1018
|
+
]),
|
|
1019
|
+
hx(
|
|
1020
|
+
'text',
|
|
1021
|
+
{ style: { color: ink, fontSize: 11, flexGrow: 1 } },
|
|
1022
|
+
`${ratio.toFixed(2)}:1`,
|
|
1023
|
+
),
|
|
1024
|
+
hx(
|
|
1025
|
+
'text',
|
|
1026
|
+
{ style: { color: colour, fontSize: 11, fontWeight: 'bold' } },
|
|
1027
|
+
grade,
|
|
1028
|
+
),
|
|
1029
|
+
);
|
|
1030
|
+
};
|
|
1031
|
+
|
|
1032
|
+
const renderPart = (part: ColorPickerPart): ReactElement | null => {
|
|
1033
|
+
switch (part) {
|
|
1034
|
+
case 'area':
|
|
1035
|
+
return renderArea();
|
|
1036
|
+
case 'hue':
|
|
1037
|
+
return renderHue();
|
|
1038
|
+
case 'alpha':
|
|
1039
|
+
return renderAlpha();
|
|
1040
|
+
case 'fields':
|
|
1041
|
+
return renderFields();
|
|
1042
|
+
case 'swatches':
|
|
1043
|
+
return swatches?.length ? renderSwatches('swatches', swatches) : null;
|
|
1044
|
+
case 'recent':
|
|
1045
|
+
return recent?.length ? renderSwatches('recent', recent) : null;
|
|
1046
|
+
case 'contrast':
|
|
1047
|
+
return renderContrast();
|
|
1048
|
+
default:
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
// `data-testname` is a runtime convention — react-x11's queries read it off
|
|
1054
|
+
// `props` — and its element declarations do not carry it, so it is attached
|
|
1055
|
+
// past the type the way `<Terminal>` does.
|
|
1056
|
+
return hx(
|
|
1057
|
+
'box',
|
|
1058
|
+
{
|
|
1059
|
+
theme,
|
|
1060
|
+
role: 'group',
|
|
1061
|
+
'aria-label': 'Colour picker',
|
|
1062
|
+
'aria-disabled': disabled || undefined,
|
|
1063
|
+
style: [s.root, style],
|
|
1064
|
+
'data-testname': props['data-testname'],
|
|
1065
|
+
} as Parameters<typeof hx<'box'>>[1],
|
|
1066
|
+
...shown.map(renderPart),
|
|
1067
|
+
children,
|
|
1068
|
+
);
|
|
1069
|
+
}
|