@a-type/ui 2.0.10 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/colors.stories.d.ts +20 -1
- package/dist/cjs/colors.stories.js +30 -5
- package/dist/cjs/colors.stories.js.map +1 -1
- package/dist/cjs/components/emojiPicker/EmojiPicker.d.ts +28 -0
- package/dist/cjs/components/emojiPicker/EmojiPicker.js +79 -0
- package/dist/cjs/components/emojiPicker/EmojiPicker.js.map +1 -0
- package/dist/cjs/components/emojiPicker/EmojiPicker.stories.d.ts +25 -0
- package/dist/cjs/components/emojiPicker/EmojiPicker.stories.js +21 -0
- package/dist/cjs/components/emojiPicker/EmojiPicker.stories.js.map +1 -0
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/components/relativeTime/RelativeTime.d.ts +10 -1
- package/dist/cjs/components/relativeTime/RelativeTime.js +17 -9
- package/dist/cjs/components/relativeTime/RelativeTime.js.map +1 -1
- package/dist/cjs/components/relativeTime/RelativeTime.stories.d.ts +19 -0
- package/dist/cjs/components/relativeTime/RelativeTime.stories.js +20 -0
- package/dist/cjs/components/relativeTime/RelativeTime.stories.js.map +1 -0
- package/dist/cjs/hooks/useStorage.d.ts +2 -0
- package/dist/cjs/hooks/useStorage.js +80 -0
- package/dist/cjs/hooks/useStorage.js.map +1 -0
- package/dist/cjs/hooks/withProps.d.ts +5 -0
- package/dist/cjs/hooks/withProps.js +7 -1
- package/dist/cjs/hooks/withProps.js.map +1 -1
- package/dist/cjs/uno/colors.js +1 -1
- package/dist/css/main.css +34 -34
- package/dist/esm/colors.stories.d.ts +20 -1
- package/dist/esm/colors.stories.js +30 -5
- package/dist/esm/colors.stories.js.map +1 -1
- package/dist/esm/components/emojiPicker/EmojiPicker.d.ts +28 -0
- package/dist/esm/components/emojiPicker/EmojiPicker.js +68 -0
- package/dist/esm/components/emojiPicker/EmojiPicker.js.map +1 -0
- package/dist/esm/components/emojiPicker/EmojiPicker.stories.d.ts +25 -0
- package/dist/esm/components/emojiPicker/EmojiPicker.stories.js +18 -0
- package/dist/esm/components/emojiPicker/EmojiPicker.stories.js.map +1 -0
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/components/relativeTime/RelativeTime.d.ts +10 -1
- package/dist/esm/components/relativeTime/RelativeTime.js +17 -9
- package/dist/esm/components/relativeTime/RelativeTime.js.map +1 -1
- package/dist/esm/components/relativeTime/RelativeTime.stories.d.ts +19 -0
- package/dist/esm/components/relativeTime/RelativeTime.stories.js +17 -0
- package/dist/esm/components/relativeTime/RelativeTime.stories.js.map +1 -0
- package/dist/esm/hooks/useStorage.d.ts +2 -0
- package/dist/esm/hooks/useStorage.js +77 -0
- package/dist/esm/hooks/useStorage.js.map +1 -0
- package/dist/esm/hooks/withProps.d.ts +5 -0
- package/dist/esm/hooks/withProps.js +5 -0
- package/dist/esm/hooks/withProps.js.map +1 -1
- package/dist/esm/uno/colors.js +1 -1
- package/package.json +4 -2
- package/src/colors.stories.tsx +30 -4
- package/src/components/emojiPicker/EmojiPicker.stories.tsx +21 -0
- package/src/components/emojiPicker/EmojiPicker.tsx +170 -0
- package/src/components/index.ts +1 -0
- package/src/components/relativeTime/RelativeTime.stories.tsx +21 -0
- package/src/components/relativeTime/RelativeTime.tsx +32 -9
- package/src/hooks/useStorage.ts +107 -0
- package/src/hooks/withProps.tsx +12 -0
- package/src/uno/colors.ts +1 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { EmojiPicker } from './EmojiPicker.js';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'EmojiPicker',
|
|
6
|
+
component: EmojiPicker,
|
|
7
|
+
argTypes: {},
|
|
8
|
+
parameters: {
|
|
9
|
+
controls: { expanded: true },
|
|
10
|
+
},
|
|
11
|
+
} satisfies Meta<typeof EmojiPicker>;
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof EmojiPicker>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
render(args) {
|
|
19
|
+
return <EmojiPicker {...args} />;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import {
|
|
3
|
+
EmojiPicker as Core,
|
|
4
|
+
EmojiPickerListCategoryHeaderProps,
|
|
5
|
+
EmojiPickerListEmojiProps,
|
|
6
|
+
EmojiPickerListProps,
|
|
7
|
+
EmojiPickerRootProps,
|
|
8
|
+
EmojiPickerViewportProps,
|
|
9
|
+
useSkinTone,
|
|
10
|
+
} from 'frimousse';
|
|
11
|
+
import { withClassName, withProps } from '../../hooks.js';
|
|
12
|
+
import { useLocalStorage } from '../../hooks/useStorage.js';
|
|
13
|
+
import { Box, BoxProps } from '../box/Box.js';
|
|
14
|
+
import { Button } from '../button/Button.js';
|
|
15
|
+
import { inputClassName } from '../input/Input.js';
|
|
16
|
+
import { Spinner } from '../spinner/Spinner.js';
|
|
17
|
+
|
|
18
|
+
export const EmojiPickerRoot = withClassName(
|
|
19
|
+
Core.Root,
|
|
20
|
+
'layer-components:(isolate flex flex-col w-fit h-368px bg-white gap-sm)',
|
|
21
|
+
);
|
|
22
|
+
export const EmojiPickerSearch = withClassName(
|
|
23
|
+
Core.Search,
|
|
24
|
+
'layer-components:(z-10)',
|
|
25
|
+
inputClassName,
|
|
26
|
+
);
|
|
27
|
+
export const EmojiPickerViewport = ({
|
|
28
|
+
className,
|
|
29
|
+
...props
|
|
30
|
+
}: EmojiPickerViewportProps) => (
|
|
31
|
+
<Box border className="flex-1 min-h-0 overflow-hidden">
|
|
32
|
+
<Core.Viewport
|
|
33
|
+
className="layer-components:(relative outline-hidden)"
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
</Box>
|
|
37
|
+
);
|
|
38
|
+
export const EmojiPickerLoading = withClassName(
|
|
39
|
+
withProps(Core.Loading, {
|
|
40
|
+
children: <Spinner />,
|
|
41
|
+
}),
|
|
42
|
+
'layer-compoennts:(absolute inset-0 flex items-center justify-center bg-inherit)',
|
|
43
|
+
);
|
|
44
|
+
export const EmojiPickerEmpty = withClassName(
|
|
45
|
+
withProps(Core.Empty, {
|
|
46
|
+
children: <>No emoji found</>,
|
|
47
|
+
}),
|
|
48
|
+
'layer-components:(absolute inset-0 flex items-center justify-center bg-inherit color-gray-dark text-xs)',
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export const EmojiPickerCategoryHeader = (
|
|
52
|
+
props: EmojiPickerListCategoryHeaderProps,
|
|
53
|
+
) => (
|
|
54
|
+
<div
|
|
55
|
+
className={clsx(
|
|
56
|
+
'layer-components:(bg-inherit px-md py-sm text-xs font-semibold text-gray-dark sticky top-0)',
|
|
57
|
+
props.className,
|
|
58
|
+
)}
|
|
59
|
+
>
|
|
60
|
+
{props.category.label}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
export const EmojiPickerRow = withClassName(
|
|
64
|
+
'div',
|
|
65
|
+
'layer-components:(scroll-my-xs px-xs)',
|
|
66
|
+
);
|
|
67
|
+
export const EmojiPickerEmoji = withClassName(
|
|
68
|
+
(p: EmojiPickerListEmojiProps) => (
|
|
69
|
+
<Button
|
|
70
|
+
{...p}
|
|
71
|
+
color="ghost"
|
|
72
|
+
toggled={p.emoji.isActive}
|
|
73
|
+
toggleMode="color"
|
|
74
|
+
size="icon-small"
|
|
75
|
+
aria-label={p.emoji.label}
|
|
76
|
+
className="text-lg p-xs"
|
|
77
|
+
>
|
|
78
|
+
{p.emoji.emoji}
|
|
79
|
+
</Button>
|
|
80
|
+
),
|
|
81
|
+
'',
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const defaultListComponents = {
|
|
85
|
+
CategoryHeader: EmojiPickerCategoryHeader,
|
|
86
|
+
Row: EmojiPickerRow,
|
|
87
|
+
Emoji: EmojiPickerEmoji,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const EmojiPickerList = ({
|
|
91
|
+
className,
|
|
92
|
+
components,
|
|
93
|
+
}: EmojiPickerListProps) => {
|
|
94
|
+
return (
|
|
95
|
+
<Core.List
|
|
96
|
+
className={clsx('layer-components:(select-none pb-md)', className)}
|
|
97
|
+
components={
|
|
98
|
+
components
|
|
99
|
+
? {
|
|
100
|
+
...defaultListComponents,
|
|
101
|
+
...components,
|
|
102
|
+
}
|
|
103
|
+
: defaultListComponents
|
|
104
|
+
}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const useEmojiSkinTone = () =>
|
|
110
|
+
useLocalStorage<SkinTone | undefined>('emoji-skin-tone', undefined, false);
|
|
111
|
+
|
|
112
|
+
export type SkinTone = ReturnType<typeof useSkinTone>[0];
|
|
113
|
+
export const EmojiPickerSkinToneSelector = (props: BoxProps) => {
|
|
114
|
+
const [_, __, options] = useSkinTone();
|
|
115
|
+
const [skinTone, setSkinTone] = useEmojiSkinTone();
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<Box d="row" gap border {...props}>
|
|
119
|
+
{options.map((option) => (
|
|
120
|
+
<Button
|
|
121
|
+
key={option.skinTone}
|
|
122
|
+
color="ghost"
|
|
123
|
+
toggled={option.skinTone === skinTone}
|
|
124
|
+
toggleMode="color"
|
|
125
|
+
size="icon-small"
|
|
126
|
+
aria-label={`Skin tone ${option}`}
|
|
127
|
+
className="text-md p-xs"
|
|
128
|
+
onClick={() => setSkinTone(option.skinTone)}
|
|
129
|
+
>
|
|
130
|
+
{option.emoji}
|
|
131
|
+
</Button>
|
|
132
|
+
))}
|
|
133
|
+
</Box>
|
|
134
|
+
);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export interface EmojiPickerProps
|
|
138
|
+
extends Omit<EmojiPickerRootProps, 'emoji' | 'onEmojiSelect'> {
|
|
139
|
+
onValueChange: (value: string, label: string) => void;
|
|
140
|
+
}
|
|
141
|
+
const EmojiPickerPrefab = ({ onValueChange, ...props }: EmojiPickerProps) => {
|
|
142
|
+
const [skinTone] = useEmojiSkinTone();
|
|
143
|
+
return (
|
|
144
|
+
<EmojiPickerRoot
|
|
145
|
+
{...props}
|
|
146
|
+
onEmojiSelect={(emoji) => onValueChange(emoji.emoji, emoji.label)}
|
|
147
|
+
skinTone={skinTone}
|
|
148
|
+
>
|
|
149
|
+
<EmojiPickerSearch />
|
|
150
|
+
<EmojiPickerViewport>
|
|
151
|
+
<EmojiPickerList />
|
|
152
|
+
<EmojiPickerLoading />
|
|
153
|
+
<EmojiPickerEmpty />
|
|
154
|
+
</EmojiPickerViewport>
|
|
155
|
+
<EmojiPickerSkinToneSelector className="mr-auto" />
|
|
156
|
+
</EmojiPickerRoot>
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const EmojiPicker = Object.assign(EmojiPickerPrefab, {
|
|
161
|
+
Root: EmojiPickerRoot,
|
|
162
|
+
Search: EmojiPickerSearch,
|
|
163
|
+
Viewport: EmojiPickerViewport,
|
|
164
|
+
List: EmojiPickerList,
|
|
165
|
+
Loading: EmojiPickerLoading,
|
|
166
|
+
Empty: EmojiPickerEmpty,
|
|
167
|
+
CategoryHeader: EmojiPickerCategoryHeader,
|
|
168
|
+
Row: EmojiPickerRow,
|
|
169
|
+
Emoji: EmojiPickerEmoji,
|
|
170
|
+
});
|
package/src/components/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export * from './dialog/index.js';
|
|
|
15
15
|
export * from './divider/index.js';
|
|
16
16
|
export * from './dropdownMenu/index.js';
|
|
17
17
|
export * from './editableText/EditableText.js';
|
|
18
|
+
export * from './emojiPicker/EmojiPicker.js';
|
|
18
19
|
export * from './errorBoundary/index.js';
|
|
19
20
|
export * from './forms/index.js';
|
|
20
21
|
export * from './horizontalList/HorizontalList.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { RelativeTime } from './RelativeTime.js';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'RelativeTime',
|
|
6
|
+
component: RelativeTime,
|
|
7
|
+
argTypes: {},
|
|
8
|
+
args: {
|
|
9
|
+
value: Date.now() + 60 * 1000 * 2,
|
|
10
|
+
abbreviate: false,
|
|
11
|
+
},
|
|
12
|
+
parameters: {
|
|
13
|
+
controls: { expanded: true },
|
|
14
|
+
},
|
|
15
|
+
} satisfies Meta<typeof RelativeTime>;
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
|
|
19
|
+
type Story = StoryObj<typeof RelativeTime>;
|
|
20
|
+
|
|
21
|
+
export const Default: Story = {};
|
|
@@ -1,45 +1,68 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { shortenTimeUnits } from '@a-type/utils';
|
|
4
|
+
import { differenceInMinutes } from 'date-fns/differenceInMinutes';
|
|
4
5
|
import { formatDistanceToNowStrict } from 'date-fns/formatDistanceToNowStrict';
|
|
5
6
|
import { useEffect, useMemo, useState } from 'react';
|
|
6
7
|
|
|
7
8
|
export interface RelativeTimeProps {
|
|
8
9
|
value: number;
|
|
9
10
|
abbreviate?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Makes it count down seconds for a future date value as it approaches.
|
|
13
|
+
* Does not affect past dates.
|
|
14
|
+
*/
|
|
15
|
+
countdownSeconds?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Remove "from now" or "ago" from the output.
|
|
18
|
+
*/
|
|
19
|
+
disableRelativeText?: boolean;
|
|
10
20
|
}
|
|
11
21
|
|
|
12
|
-
function formatDistanceToNow(date: Date) {
|
|
22
|
+
function formatDistanceToNow(date: Date, relativeText = true) {
|
|
13
23
|
const now = Date.now();
|
|
14
24
|
if (Math.abs(date.getTime() - now) < 1000) {
|
|
15
25
|
return 'just now';
|
|
16
26
|
}
|
|
17
27
|
return (
|
|
18
28
|
formatDistanceToNowStrict(date) +
|
|
19
|
-
(date.getTime() < now ? ' ago' : ' from now')
|
|
29
|
+
(relativeText ? (date.getTime() < now ? ' ago' : ' from now') : '')
|
|
20
30
|
);
|
|
21
31
|
}
|
|
22
32
|
|
|
23
|
-
export function RelativeTime({
|
|
33
|
+
export function RelativeTime({
|
|
34
|
+
value,
|
|
35
|
+
abbreviate,
|
|
36
|
+
countdownSeconds,
|
|
37
|
+
disableRelativeText,
|
|
38
|
+
}: RelativeTimeProps) {
|
|
24
39
|
const asDate = useMemo(() => new Date(value), [value]);
|
|
25
40
|
const [time, setTime] = useState(() =>
|
|
26
41
|
abbreviate
|
|
27
|
-
? shortenTimeUnits(formatDistanceToNow(asDate))
|
|
28
|
-
: formatDistanceToNow(asDate),
|
|
42
|
+
? shortenTimeUnits(formatDistanceToNow(asDate, !disableRelativeText))
|
|
43
|
+
: formatDistanceToNow(asDate, !disableRelativeText),
|
|
29
44
|
);
|
|
45
|
+
// increase update rate if the date is less than 1 minute away and in the future
|
|
46
|
+
// (past is ok to just leave ~1 minute)
|
|
47
|
+
const updateRate =
|
|
48
|
+
countdownSeconds &&
|
|
49
|
+
asDate.getTime() > Date.now() &&
|
|
50
|
+
Math.abs(differenceInMinutes(asDate, new Date())) < 1
|
|
51
|
+
? 1000
|
|
52
|
+
: 60 * 1000;
|
|
30
53
|
|
|
31
54
|
useEffect(() => {
|
|
32
55
|
const update = () => {
|
|
33
56
|
setTime(
|
|
34
57
|
abbreviate
|
|
35
|
-
? shortenTimeUnits(formatDistanceToNow(asDate))
|
|
36
|
-
: formatDistanceToNow(asDate),
|
|
58
|
+
? shortenTimeUnits(formatDistanceToNow(asDate, !disableRelativeText))
|
|
59
|
+
: formatDistanceToNow(asDate, !disableRelativeText),
|
|
37
60
|
);
|
|
38
61
|
};
|
|
39
|
-
const interval = setInterval(update,
|
|
62
|
+
const interval = setInterval(update, updateRate);
|
|
40
63
|
update();
|
|
41
64
|
return () => clearInterval(interval);
|
|
42
|
-
}, [asDate, abbreviate]);
|
|
65
|
+
}, [asDate, abbreviate, updateRate, disableRelativeText]);
|
|
43
66
|
|
|
44
67
|
return <>{time}</>;
|
|
45
68
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { useEffect, useMemo } from 'react';
|
|
2
|
+
import { proxy, useSnapshot } from 'valtio';
|
|
3
|
+
|
|
4
|
+
function makeUseStorage(
|
|
5
|
+
storage: Storage,
|
|
6
|
+
cache: Record<string, any>,
|
|
7
|
+
name: string = storage.constructor.name,
|
|
8
|
+
) {
|
|
9
|
+
return function useStorage<T>(
|
|
10
|
+
key: string,
|
|
11
|
+
initialValue: T,
|
|
12
|
+
writeInitialValue = false,
|
|
13
|
+
) {
|
|
14
|
+
// using useMemo to execute synchronous code in render just once.
|
|
15
|
+
// this hook comes before useLocalStorageCache because we want to load
|
|
16
|
+
// values into the cache before accessing them.
|
|
17
|
+
useMemo(() => {
|
|
18
|
+
if (typeof window === 'undefined') return;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const stored = storage.getItem(key);
|
|
22
|
+
if (stored) {
|
|
23
|
+
cache[key] = JSON.parse(stored);
|
|
24
|
+
}
|
|
25
|
+
} catch (err) {
|
|
26
|
+
console.error(`Error loading use-${name} value for ${key}: ${err}`);
|
|
27
|
+
storage.removeItem(key);
|
|
28
|
+
}
|
|
29
|
+
}, [key]);
|
|
30
|
+
const snapshot = useSnapshot(cache);
|
|
31
|
+
const storedValue = (snapshot[key] ?? initialValue) as T;
|
|
32
|
+
|
|
33
|
+
const hasValue = snapshot[key] !== undefined;
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!hasValue && writeInitialValue) {
|
|
36
|
+
storage.setItem(key, JSON.stringify(initialValue));
|
|
37
|
+
}
|
|
38
|
+
}, [hasValue, initialValue, writeInitialValue, key]);
|
|
39
|
+
|
|
40
|
+
// Return a wrapped version of useState's setter function that
|
|
41
|
+
// persists the new value to localStorage. It's throttled to prevent
|
|
42
|
+
// frequent writes to localStorage, which can be costly.
|
|
43
|
+
const setValue = useMemo(
|
|
44
|
+
() =>
|
|
45
|
+
throttle(
|
|
46
|
+
(value: T | ((current: T) => T)) => {
|
|
47
|
+
if (typeof window === 'undefined') return;
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
// Allow value to be a function so we have same API as useState
|
|
51
|
+
const valueToStore =
|
|
52
|
+
value instanceof Function ? value(storedValue) : value;
|
|
53
|
+
// Save to local storage
|
|
54
|
+
storage.setItem(key, JSON.stringify(valueToStore));
|
|
55
|
+
// sync it to other instances of the hook via the global cache
|
|
56
|
+
cache[key] = valueToStore;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error(
|
|
59
|
+
`Error setting use-${name} value for ${key}: ${value}: ${error}`,
|
|
60
|
+
);
|
|
61
|
+
throw new Error('Error setting value');
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
300,
|
|
65
|
+
{ trailing: true, leading: true },
|
|
66
|
+
),
|
|
67
|
+
[key, storedValue],
|
|
68
|
+
) as (value: T | ((current: T) => T)) => void;
|
|
69
|
+
|
|
70
|
+
return [storedValue, setValue] as const;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const useLocalStorage = makeUseStorage(
|
|
75
|
+
localStorage,
|
|
76
|
+
proxy({}),
|
|
77
|
+
'LocalStorage',
|
|
78
|
+
);
|
|
79
|
+
export const useSessionStorage = makeUseStorage(
|
|
80
|
+
sessionStorage,
|
|
81
|
+
proxy({}),
|
|
82
|
+
'SessionStorage',
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
function throttle(
|
|
86
|
+
func: (...args: any[]) => any,
|
|
87
|
+
wait: number,
|
|
88
|
+
options?: { trailing?: boolean; leading?: boolean },
|
|
89
|
+
): (...args: any[]) => any {
|
|
90
|
+
let previous = 0;
|
|
91
|
+
return function (this: any, ...args: any[]) {
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
if (!previous && options?.leading === false) previous = now;
|
|
94
|
+
const remaining = wait - (now - previous);
|
|
95
|
+
if (remaining <= 0) {
|
|
96
|
+
if (options?.trailing === false) previous = now;
|
|
97
|
+
return func(...args);
|
|
98
|
+
}
|
|
99
|
+
if (options?.trailing === false) {
|
|
100
|
+
return func(...args);
|
|
101
|
+
}
|
|
102
|
+
return setTimeout(() => {
|
|
103
|
+
previous = options?.leading === false ? 0 : Date.now();
|
|
104
|
+
func(...args);
|
|
105
|
+
}, remaining);
|
|
106
|
+
};
|
|
107
|
+
}
|
package/src/hooks/withProps.tsx
CHANGED
|
@@ -8,3 +8,15 @@ export const withProps = <T extends {}>(
|
|
|
8
8
|
return <Component {...props} {...extras} />;
|
|
9
9
|
};
|
|
10
10
|
};
|
|
11
|
+
|
|
12
|
+
type OptionalKeys<T> = {
|
|
13
|
+
[K in keyof T]-?: undefined extends T[K] ? K : never;
|
|
14
|
+
}[keyof T];
|
|
15
|
+
export const withoutProps = <T extends {}, P extends OptionalKeys<T>>(
|
|
16
|
+
Component: React.ComponentType<T>,
|
|
17
|
+
remove: P[],
|
|
18
|
+
) => {
|
|
19
|
+
return (props: Omit<T, P>) => {
|
|
20
|
+
return <Component {...(props as any)} />;
|
|
21
|
+
};
|
|
22
|
+
};
|
package/src/uno/colors.ts
CHANGED
|
@@ -7,7 +7,7 @@ export const colorConstants = `
|
|
|
7
7
|
|
|
8
8
|
export const dynamicThemeComputedColors = (name: string) => `
|
|
9
9
|
--color-${name}: oklch(calc(90% - 35% * var(--dyn-source-mode-adjust, 0) - (var(--dyn-mode-sign, 1) * var(--dyn-${name}-base-dim, 0%))) calc(var(--dyn-${name}-sat-mult,1) * (35% - 2% * var(--dyn-source-mode-adjust, 0))) var(--dyn-${name}-source, 0));
|
|
10
|
-
--color-${name}-wash: oklch(from var(--color-${name}) calc(min(0.999,max(0.15, l + 0.15 * var(--dyn-mode-mult, 1)))) calc(var(--dyn-${name}-sat-mult) * (c * var(--dyn-saturation-x-wash, 1) - 0.
|
|
10
|
+
--color-${name}-wash: oklch(from var(--color-${name}) calc(min(0.999,max(0.15, l + 0.15 * var(--dyn-mode-mult, 1)))) calc(var(--dyn-${name}-sat-mult) * (c * var(--dyn-saturation-x-wash, 1) - 0.06)) calc(h - 5 * var(--dyn-${name}-hue-rotate, 0) * var(--dyn-${name}-hue-rotate-mult, 1)));
|
|
11
11
|
--color-${name}-light: oklch(from var(--color-${name}) calc(l + 0.08 * var(--dyn-mode-mult, 1)) calc(var(--dyn-${name}-sat-mult) * (c * var(--dyn-saturation-x-light, 1) - 0.03)) calc(h - 0.5 * var(--dyn-${name}-hue-rotate, 0) * var(--dyn-${name}-hue-rotate-mult, 1)));
|
|
12
12
|
--color-${name}-dark: oklch(from var(--color-${name}) calc(l - 0.26 * var(--dyn-mode-mult, 1)) calc(var(--dyn-${name}-sat-mult) * (c * var(--dyn-saturation-x-dark, 1) + 0.01)) calc(h + 0.2 * var(--dyn-${name}-hue-rotate, 0) * var(--dyn-${name}-hue-rotate-mult, 1)));
|
|
13
13
|
--color-${name}-ink: oklch(from var(--color-${name}) calc(l - 0.45 * var(--dyn-mode-mult, 1)) calc(var(--dyn-${name}-sat-mult) * (c * var(--dyn-saturation-x-ink, 1) + 0.01)) calc(h + 1 * var(--dyn-${name}-hue-rotate, 0) * var(--dyn-${name}-hue-rotate-mult, 1)));
|