Skip to content

Commit

Permalink
feat: Added eye-dropper hook (improved).
Browse files Browse the repository at this point in the history
  • Loading branch information
Blankeos committed Oct 20, 2024
1 parent a52b108 commit 4b095ac
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 2 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Based on the [@mantine/hooks](https://github.com/mantinedev/mantine/tree/master/
- [ ] use-document-title
- [ ] use-document-visibility
- [ ] use-event-listener
- [ ] use-eye-dropper
- [x] use-eye-dropper (improved, state management is inside the hook)
- [x] use-favicon (improved, more flexible)
- [ ] use-fetch
- [ ] use-focus-return
Expand All @@ -74,7 +74,7 @@ Based on the [@mantine/hooks](https://github.com/mantinedev/mantine/tree/master/
- [x] use-hotkeys
- [x] use-hover
- [x] ~~use-id~~ (Solid has [`createUniqueId`](https://docs.solidjs.com/reference/component-apis/create-unique-id))
- [x] use-idle (There is [`createIdleTimer`](https://primitives.solidjs.community/package/idle/) solid-primitives as well)
- [x] use-idle (Added, but note that there is [`createIdleTimer`](https://primitives.solidjs.community/package/idle/) solid-primitives as well)
- [ ] use-in-viewport
- [ ] use-input-state
- [ ] use-intersection
Expand Down
19 changes: 19 additions & 0 deletions dev/components/examples/use-eye-dropper/use-eye-dropper.code.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
```tsx
const { color, supported, pickColor } = useEyeDropper();

return (
<div>
<button onClick={pickColor} disabled={!supported()}>
Pick Color
</button>

<div>
Current Color: <span style={{ height: 32, width: 32, 'background-color': color() }} />
</div>

<Show when={supported() !== undefined && !supported()}>
<span>Your browser does not support EyeDropper.</span>
</Show>
</div>
);
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useEyeDropper } from 'src';
import { ExampleBase } from '../example-base';
import Code from './use-eye-dropper.code.mdx';

import { IconEyeDropper } from 'dev/icons';
import { Show } from 'solid-js';
import { useMDXComponents } from 'solid-jsx';

export function UseEyeDropperExample() {
const { color, supported, pickColor } = useEyeDropper();

// @ts-ignore
const components: any = useMDXComponents();

return (
<ExampleBase
title="useEyeDropper"
description="A hook that gives you the ability to open the browser's EyeDropper API and save it to a signal."
code={<Code components={components} />}
>
<div class="flex h-full w-full flex-col items-center justify-center gap-5 rounded-md border p-3 py-10 text-center">
<div class="flex items-center gap-x-2">
<button class="transition active:scale-95" onClick={pickColor} disabled={!supported()}>
<IconEyeDropper />
</button>

<div class="flex items-center gap-x-2 text-sm">
Picked Color: {color()}
<div class="h-8 w-8 rounded-full border" style={{ 'background-color': color() }} />
</div>
</div>

<Show when={supported() !== undefined && !supported()}>
<span class="text-xs text-red-500">Your browser does not support EyeDropper.</span>
</Show>
</div>
</ExampleBase>
);
}
15 changes: 15 additions & 0 deletions dev/icons/eye-dropper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { JSX, VoidProps } from 'solid-js';

export default function EyeDropper(props: VoidProps<JSX.SvgSVGAttributes<SVGSVGElement>>) {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256" {...props}>
<g fill="currentColor">
<path
d="m207.8 87.6l-25.37 25.53l4.89 4.88a16 16 0 0 1 0 22.64l-9 9a8 8 0 0 1-11.32 0l-60.68-60.7a8 8 0 0 1 0-11.32l9-9a16 16 0 0 1 22.63 0l4.88 4.89l25-25.11c10.79-10.79 28.37-11.45 39.45-1a28 28 0 0 1 .52 40.19"
opacity=".2"
/>
<path d="M224 67.3a35.8 35.8 0 0 0-11.26-25.66c-14-13.28-36.72-12.78-50.62 1.13L142.8 62.2a24 24 0 0 0-33.14.77l-9 9a16 16 0 0 0 0 22.64l2 2.06l-51 51a39.75 39.75 0 0 0-10.53 38l-8 18.41A13.68 13.68 0 0 0 36 219.3a15.92 15.92 0 0 0 17.71 3.35L71.23 215a39.89 39.89 0 0 0 37.06-10.75l51-51l2.06 2.06a16 16 0 0 0 22.62 0l9-9a24 24 0 0 0 .74-33.18l19.75-19.87A35.75 35.75 0 0 0 224 67.3M97 193a24 24 0 0 1-24 6a8 8 0 0 0-5.55.31l-18.1 7.91L57 189.41a8 8 0 0 0 .25-5.75A23.88 23.88 0 0 1 63 159l51-51l33.94 34ZM202.13 82l-25.37 25.52a8 8 0 0 0 0 11.3l4.89 4.89a8 8 0 0 1 0 11.32l-9 9L112 83.26l9-9a8 8 0 0 1 11.31 0l4.89 4.89a8 8 0 0 0 5.65 2.34a8 8 0 0 0 5.66-2.36l24.94-25.09c7.81-7.82 20.5-8.18 28.29-.81a20 20 0 0 1 .39 28.7Z" />
</g>
</svg>
);
}
5 changes: 5 additions & 0 deletions dev/pages/index/+Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import packageJSON from 'src/../package.json';
// Hooks
import { UseClickOutsideExample } from 'dev/components/examples/use-click-outside/use-click-outside.example';
import { UseElementSizeExample } from 'dev/components/examples/use-element-size/use-element-size.example';
import { UseEyeDropperExample } from 'dev/components/examples/use-eye-dropper/use-eye-dropper.example';
import { UseFaviconExample } from 'dev/components/examples/use-favicon/use-favicon.example';
import { UseHotkeysExample } from 'dev/components/examples/use-hotkeys/use-hotkeys.example';
import { UseHoverExample } from 'dev/components/examples/use-hover/use-hover.example';
Expand Down Expand Up @@ -90,6 +91,10 @@ export default function HomePage() {
title: 'useLocalStorage',
example: <UseLocalStorageExample />,
},
{
title: 'useEyeDropper',
example: <UseEyeDropperExample />,
},
];

const filteredList = createMemo(() => {
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './use-click-outside/use-click-outside';
export * from './use-eye-dropper/use-eye-dropper';
export * from './use-favicon/use-favicon';
export * from './use-hotkeys/use-hotkeys';
export * from './use-hover/use-hover';
Expand Down
66 changes: 66 additions & 0 deletions src/use-eye-dropper/use-eye-dropper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { createSignal, onMount } from 'solid-js';

interface EyeDropperOpenOptions {
signal?: AbortSignal;
}

export interface EyeDropperOpenReturnType {
sRGBHex: string;
}

function isOpera() {
return navigator.userAgent.includes('OPR');
}

/**
* A hook that opens the browser's EyeDropper API.
*
* This has an improvement over Mantine's API. Mantine's is more low-level. Bagon
* prepares states for you by default.
*/
export function useEyeDropper() {
const [color, setColor] = createSignal<string>();
const [error, setError] = createSignal<Error | null>(null);
const [supported, setSupported] = createSignal<boolean>();

onMount(() => {
setSupported(typeof window !== 'undefined' && !isOpera() && 'EyeDropper' in window);
});

const open = (
options: EyeDropperOpenOptions = {},
): Promise<EyeDropperOpenReturnType | undefined> => {
if (supported()) {
const eyeDropper = new (window as any).EyeDropper();
return eyeDropper.open(options);
}

return Promise.resolve(undefined);
};

const pickColor = async () => {
try {
const { sRGBHex } = (await open())!;
setColor(sRGBHex);
} catch (e) {
setError(e as Error);
}
};

return {
/**
* Improved in bagon.
* - true - supported.
* - false - not supported.
* - undefined - support is not checked yet (initial state so you can check this if you don't want a flicker before support is determined).
*/
supported,
open,
/** Added in bagon. */
error,
/** Added in bagon. */
color,
/** Added in bagon. */
pickColor,
};
}

0 comments on commit 4b095ac

Please sign in to comment.