tinywidgets 1.2.4 → 1.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tinywidgets",
3
- "version": "1.2.4",
3
+ "version": "1.3.1",
4
4
  "author": "jamesgpearce",
5
5
  "repository": "github:tinyplex/tinywidgets",
6
6
  "license": "MIT",
@@ -11,7 +11,7 @@ import {
11
11
  } from './index.css.ts';
12
12
 
13
13
  /**
14
- * The `Button` component displays an button, with a number of common variants.
14
+ * The `Button` component displays a button, with a number of common variants.
15
15
  *
16
16
  * @param props The props for the component.
17
17
  * @returns The Button component.
@@ -0,0 +1,14 @@
1
+ import {style} from '@vanilla-extract/css';
2
+ import {colors} from '../../css/colors.css';
3
+ import {dimensions} from '../../css/dimensions.css';
4
+
5
+ export const select = style({
6
+ borderRadius: dimensions.radius,
7
+ padding: '0.5rem',
8
+ outlineOffset: '2px',
9
+ color: 'inherit',
10
+ transition: 'background-color 0.1s,border-color 0.1s',
11
+ boxShadow: colors.shadow,
12
+ border: colors.border,
13
+ backgroundColor: colors.background,
14
+ });
@@ -0,0 +1,77 @@
1
+ import {useCallback, useState} from 'react';
2
+ import {classNames} from '../../common/functions.tsx';
3
+ import {select} from './index.css.ts';
4
+
5
+ /**
6
+ * The `Select` component displays a managed select input with an existing
7
+ * value.
8
+ *
9
+ * @param props The props for the component.
10
+ * @returns The Select component.
11
+ * @example
12
+ * ```tsx
13
+ * <Select
14
+ * initialOption="CA"
15
+ * options={{ AL: 'Albania', BE: 'Belgium', CA: 'Canada' }}
16
+ * onChange={(option) => console.log(option)}
17
+ * />
18
+ * ```
19
+ * @icon Lucide.Combine
20
+ */
21
+ export const Select = ({
22
+ options,
23
+ initialOption,
24
+ onChange,
25
+ alt,
26
+ className,
27
+ ref,
28
+ }: {
29
+ /**
30
+ * The options and labels to show in the select widget.
31
+ */
32
+ readonly options: {[option: string]: string};
33
+ /**
34
+ * An optional initial option.
35
+ */
36
+ readonly initialOption?: string;
37
+ /**
38
+ * A handler called when the option is changed.
39
+ */
40
+ readonly onChange?: (option: string) => void;
41
+ /**
42
+ * Alternative text shown when the user hovers over the input.
43
+ */
44
+ readonly alt?: string;
45
+ /**
46
+ * An extra CSS class name for the component.
47
+ */
48
+ readonly className?: string;
49
+ ref?: React.RefObject<HTMLSelectElement | null>;
50
+ }) => {
51
+ const [option, setOption] = useState(initialOption ?? '');
52
+ const handleChange = useCallback(
53
+ ({target: {value}}: React.ChangeEvent<HTMLSelectElement>) => {
54
+ setOption(value);
55
+ onChange?.(value);
56
+ },
57
+ [onChange],
58
+ );
59
+ return (
60
+ <select
61
+ className={classNames(select, className)}
62
+ onChange={handleChange}
63
+ title={alt}
64
+ ref={ref}
65
+ >
66
+ {Object.entries(options).map(([eachOption, label]) => (
67
+ <option
68
+ key={eachOption}
69
+ value={eachOption}
70
+ {...(eachOption === option ? {selected: true} : {})}
71
+ >
72
+ {label}
73
+ </option>
74
+ ))}
75
+ </select>
76
+ );
77
+ };
@@ -0,0 +1,36 @@
1
+ import {style} from '@vanilla-extract/css';
2
+ import {colors} from '../../css/colors.css';
3
+ import {dimensions} from '../../css/dimensions.css';
4
+
5
+ export const wrapper = style({
6
+ flexShrink: 0,
7
+ alignSelf: 'center',
8
+ position: 'relative',
9
+ });
10
+
11
+ export const wrapperWithIcon = style({});
12
+
13
+ export const input = style({
14
+ borderRadius: dimensions.radius,
15
+ padding: '0.5rem',
16
+ outlineOffset: '2px',
17
+ color: 'inherit',
18
+ transition: 'background-color 0.1s,border-color 0.1s',
19
+ boxShadow: colors.shadow + ' inset',
20
+ border: colors.border,
21
+ backgroundColor: colors.background,
22
+ });
23
+
24
+ export const inputWithIcon = style({
25
+ textIndent: `calc(${dimensions.icon} * 1.3)`,
26
+ });
27
+
28
+ export const icon = style({
29
+ position: 'absolute',
30
+ left: `calc(${dimensions.icon} * .5)`,
31
+ top: `calc(${dimensions.icon} * .65)`,
32
+ color: colors.foregroundDim,
33
+ backgroundColor: colors.background,
34
+ borderRight: `calc(${dimensions.icon} * .25) solid ${colors.background}`,
35
+ boxSizing: 'content-box',
36
+ });
@@ -0,0 +1,91 @@
1
+ import {useCallback, useState, type ComponentType} from 'react';
2
+ import {classNames} from '../../common/functions.tsx';
3
+ import {iconSize} from '../../css/dimensions.css.ts';
4
+ import {
5
+ icon,
6
+ input,
7
+ inputWithIcon,
8
+ wrapper,
9
+ wrapperWithIcon,
10
+ } from './index.css.ts';
11
+
12
+ /**
13
+ * The `TextInput` component displays a managed text input with an existing
14
+ * value.
15
+ *
16
+ * @param props The props for the component.
17
+ * @returns The TextInput component.
18
+ * @example
19
+ * ```tsx
20
+ * <TextInput
21
+ * initialText="42"
22
+ * onChange={(value) => console.log(value)}
23
+ * />
24
+ * ```
25
+ * This example shows the TextInput component.
26
+ * @example
27
+ * ```tsx
28
+ * <TextInput icon={Lucide.Search} placeholder="Search..." />
29
+ * ```
30
+ * This example shows the TextInput component with an inset icon and
31
+ * placeholder.
32
+ * @icon Lucide.TextCursorInput
33
+ */
34
+ export const TextInput = ({
35
+ initialText,
36
+ placeholder,
37
+ onChange,
38
+ icon: Icon,
39
+ alt,
40
+ className,
41
+ ref,
42
+ }: {
43
+ /**
44
+ * An optional initial text value.
45
+ */
46
+ readonly initialText?: string;
47
+ /**
48
+ * An optional placeholder string.
49
+ */
50
+ readonly placeholder?: string;
51
+ /**
52
+ * A handler called when the text is changed.
53
+ */
54
+ readonly onChange?: (text: string) => void;
55
+ /**
56
+ * An optional component which renders an icon on the left of the input, and
57
+ * which must accept a className prop.
58
+ */
59
+ readonly icon?: ComponentType<{className?: string}>;
60
+ /**
61
+ * Alternative text shown when the user hovers over the input.
62
+ */
63
+ readonly alt?: string;
64
+ /**
65
+ * An extra CSS class name for the component.
66
+ */
67
+ readonly className?: string;
68
+ ref?: React.RefObject<HTMLInputElement | null>;
69
+ }) => {
70
+ const [text, setText] = useState(initialText ?? '');
71
+ const handleChange = useCallback(
72
+ ({target: {value}}: React.ChangeEvent<HTMLInputElement>) => {
73
+ setText(value);
74
+ onChange?.(value);
75
+ },
76
+ [onChange],
77
+ );
78
+ return (
79
+ <div className={classNames(wrapper, Icon && wrapperWithIcon)}>
80
+ {Icon ? <Icon className={classNames(iconSize, icon)} /> : null}
81
+ <input
82
+ value={text}
83
+ placeholder={placeholder}
84
+ className={classNames(input, Icon && inputWithIcon, className)}
85
+ onChange={handleChange}
86
+ title={alt}
87
+ ref={ref}
88
+ />
89
+ </div>
90
+ );
91
+ };
@@ -20,9 +20,11 @@ import {
20
20
  * - `background2`
21
21
  * - `backgroundHaze`
22
22
  * - `backgroundHover`
23
+ * - `backgroundExtreme`
23
24
  * - `foreground`
24
25
  * - `foregroundBright`
25
26
  * - `foregroundDim`
27
+ * - `foregroundExtreme`
26
28
  * - `border`
27
29
  * - `shadow`
28
30
  *
@@ -72,9 +74,11 @@ export const colors = createThemeContract({
72
74
  background2: null,
73
75
  backgroundHaze: null,
74
76
  backgroundHover: null,
77
+ backgroundExtreme: null,
75
78
  foreground: null,
76
79
  foregroundBright: null,
77
80
  foregroundDim: null,
81
+ foregroundExtreme: null,
78
82
  border: null,
79
83
  shadow: null,
80
84
  });
@@ -97,9 +101,11 @@ export const colorsLight = createTheme(colors, {
97
101
  background2: `oklch(95% .01 ${colors.backgroundHue})`,
98
102
  backgroundHaze: `oklch(99% .01 ${colors.backgroundHue} / .5)`,
99
103
  backgroundHover: `oklch(90% .01 ${colors.backgroundHue})`,
104
+ backgroundExtreme: '#fff',
100
105
  foreground: `oklch(50% .01 ${colors.accentHue})`,
101
106
  foregroundBright: `oklch(10% .01 ${colors.accentHue})`,
102
107
  foregroundDim: `oklch(60% .01 ${colors.accentHue})`,
108
+ foregroundExtreme: '#000',
103
109
  border: `1px solid oklch(90% .01 ${colors.backgroundHue})`,
104
110
  shadow: '0 1px 4px 0 hsl(0 0 20 / .1)',
105
111
  });
@@ -113,9 +119,11 @@ export const colorsDark = createTheme(colors, {
113
119
  background2: `oklch(15% .01 ${colors.backgroundHue})`,
114
120
  backgroundHaze: `oklch(21% 0% ${colors.backgroundHue} / .5)`,
115
121
  backgroundHover: `oklch(25% .01 ${colors.backgroundHue})`,
122
+ backgroundExtreme: '#000',
116
123
  foreground: `oklch(85% .01 ${colors.accentHue})`,
117
124
  foregroundBright: `oklch(95% .01 ${colors.accentHue})`,
118
125
  foregroundDim: `oklch(60% .01 ${colors.accentHue})`,
126
+ foregroundExtreme: '#fff',
119
127
  border: `1px solid oklch(30% .01 ${colors.backgroundHue})`,
120
128
  shadow: '0 1px 4px 0 #000',
121
129
  });
package/src/index.ts CHANGED
@@ -8,8 +8,10 @@ export {Hr} from './components/Hr/index.tsx';
8
8
  export {Image} from './components/Image/index.tsx';
9
9
  export {Metric} from './components/Metric/index.tsx';
10
10
  export {Row} from './components/Row/index.tsx';
11
+ export {Select} from './components/Select/index.tsx';
11
12
  export {Summary} from './components/Summary/index.tsx';
12
13
  export {Tag} from './components/Tag/index.tsx';
14
+ export {TextInput} from './components/TextInput/index.tsx';
13
15
 
14
16
  export {classNames} from './common/functions.tsx';
15
17
  export {useDark} from './stores/LocalStore.tsx';