tinywidgets 1.2.4 → 1.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tinywidgets",
3
- "version": "1.2.4",
3
+ "version": "1.3.0",
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
+ };
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';