tinywidgets 1.1.5 → 1.2.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/bun.lock +778 -0
- package/eslint.config.js +0 -41
- package/package.json +13 -13
- package/src/components/App/index.css.ts +21 -0
- package/src/components/App/index.tsx +22 -1
- package/src/components/Button/index.tsx +99 -102
- package/src/css/dimensions.css.ts +2 -0
- package/src/index.ts +0 -6
- package/.prettierignore +0 -1
- package/bun.lockb +0 -0
- package/src/components/TasksProvider/index.tsx +0 -309
package/eslint.config.js
CHANGED
|
@@ -138,47 +138,6 @@ export default tsLint.config(
|
|
|
138
138
|
},
|
|
139
139
|
},
|
|
140
140
|
|
|
141
|
-
{
|
|
142
|
-
files: ['src/@types/**/*.js'],
|
|
143
|
-
settings: {jsdoc: {mode: 'typescript', contexts: ['any']}},
|
|
144
|
-
rules: {
|
|
145
|
-
'jsdoc/check-tag-names': [
|
|
146
|
-
2,
|
|
147
|
-
{definedTags: ['category', 'packageDocumentation']},
|
|
148
|
-
],
|
|
149
|
-
'jsdoc/no-restricted-syntax': [
|
|
150
|
-
2,
|
|
151
|
-
{
|
|
152
|
-
contexts: [
|
|
153
|
-
{
|
|
154
|
-
comment:
|
|
155
|
-
// eslint-disable-next-line max-len
|
|
156
|
-
'JsdocBlock:not(:has(JsdocTag[tag=/category|packageDocumentation/]))',
|
|
157
|
-
message: 'Every non-module block requires a @category tag',
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
comment: 'JsdocBlock:not(:has(JsdocTag[tag=since]))',
|
|
161
|
-
message: 'Every block requires a @since tag',
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
comment:
|
|
165
|
-
'JsdocBlock:has(JsdocTag[tag=since] ~ JsdocTag[tag=since])',
|
|
166
|
-
message: 'Every block must have only one @since tag',
|
|
167
|
-
},
|
|
168
|
-
],
|
|
169
|
-
},
|
|
170
|
-
],
|
|
171
|
-
'jsdoc/require-jsdoc': 2,
|
|
172
|
-
'jsdoc/require-description': 2,
|
|
173
|
-
'jsdoc/require-description-complete-sentence': 2,
|
|
174
|
-
'jsdoc/require-returns-description': 2,
|
|
175
|
-
'jsdoc/no-blank-blocks': 2,
|
|
176
|
-
'jsdoc/require-param-type': 0,
|
|
177
|
-
'jsdoc/require-returns-type': 0,
|
|
178
|
-
'jsdoc/check-param-names': 0,
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
|
|
182
141
|
{
|
|
183
142
|
files: ['eslint.config.js'],
|
|
184
143
|
extends: [tsLint.configs.disableTypeChecked],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tinywidgets",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"author": "jamesgpearce",
|
|
5
5
|
"repository": "github:tinyplex/tinywidgets",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,28 +19,28 @@
|
|
|
19
19
|
"prePublishPackage": "prettier --check . && eslint . && cspell --quiet . && tsc && cp ../README.md ./README.md"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"eslint
|
|
22
|
+
"@eslint/js": "^9.25.1",
|
|
23
|
+
"@types/react": "^19.1.2",
|
|
24
|
+
"cspell": "^8.19.3",
|
|
25
|
+
"eslint": "^9.25.1",
|
|
26
|
+
"eslint-plugin-import": "^2.31.0",
|
|
27
|
+
"eslint-plugin-react": "^7.37.5",
|
|
26
28
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
29
|
+
"globals": "^16.0.0",
|
|
27
30
|
"prettier": "^3.5.3",
|
|
28
31
|
"prettier-plugin-organize-imports": "^4.1.0",
|
|
29
|
-
"typescript": "^5.8.
|
|
32
|
+
"typescript": "^5.8.3",
|
|
33
|
+
"typescript-eslint": "^8.31.0"
|
|
30
34
|
},
|
|
31
35
|
"exports": {
|
|
32
36
|
".": "./src/index.ts",
|
|
33
37
|
"./css": "./src/index.css.ts"
|
|
34
38
|
},
|
|
35
39
|
"dependencies": {
|
|
36
|
-
"@eslint/js": "^9.23.0",
|
|
37
40
|
"@vanilla-extract/css": "^1.17.1",
|
|
38
|
-
"
|
|
39
|
-
"globals": "^16.0.0",
|
|
40
|
-
"lucide-react": "^0.485.0",
|
|
41
|
+
"lucide-react": "^0.503.0",
|
|
41
42
|
"react": "^19.1.0",
|
|
42
43
|
"react-dom": "^19.1.0",
|
|
43
|
-
"tinybase": "^6.0.
|
|
44
|
-
"typescript-eslint": "^8.28.0"
|
|
44
|
+
"tinybase": "^6.0.4"
|
|
45
45
|
}
|
|
46
|
-
}
|
|
46
|
+
}
|
|
@@ -78,3 +78,24 @@ export const mainHasSideNav = style(
|
|
|
78
78
|
paddingLeft: `calc(${dimensions.sideNavWidth} + ${dimensions.padding})`,
|
|
79
79
|
}),
|
|
80
80
|
);
|
|
81
|
+
|
|
82
|
+
export const mainHasFooter = style({
|
|
83
|
+
paddingBottom: `calc(${dimensions.footerHeight} + ${dimensions.padding})`,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export const footer = style({
|
|
87
|
+
display: 'flex',
|
|
88
|
+
justifyContent: 'right',
|
|
89
|
+
alignItems: 'center',
|
|
90
|
+
gap: dimensions.padding,
|
|
91
|
+
padding: dimensions.padding,
|
|
92
|
+
position: 'fixed',
|
|
93
|
+
bottom: 0,
|
|
94
|
+
left: 0,
|
|
95
|
+
right: 0,
|
|
96
|
+
height: dimensions.footerHeight,
|
|
97
|
+
backgroundColor: colors.backgroundHaze,
|
|
98
|
+
borderTop: colors.border,
|
|
99
|
+
boxShadow: colors.shadow,
|
|
100
|
+
backdropFilter: 'blur(8px)',
|
|
101
|
+
});
|
|
@@ -23,8 +23,10 @@ import {Button} from '../Button/index.tsx';
|
|
|
23
23
|
import {
|
|
24
24
|
app,
|
|
25
25
|
appLayout,
|
|
26
|
+
footer,
|
|
26
27
|
header,
|
|
27
28
|
main,
|
|
29
|
+
mainHasFooter,
|
|
28
30
|
mainHasSideNav,
|
|
29
31
|
sideNav,
|
|
30
32
|
sideNavButton,
|
|
@@ -83,6 +85,11 @@ export const App = (props: {
|
|
|
83
85
|
* the application.
|
|
84
86
|
*/
|
|
85
87
|
readonly main?: ComponentType | ReactNode;
|
|
88
|
+
/**
|
|
89
|
+
* An optional component, element, or string which renders the footer of
|
|
90
|
+
* the application.
|
|
91
|
+
*/
|
|
92
|
+
readonly footer?: ComponentType | ReactNode;
|
|
86
93
|
/**
|
|
87
94
|
* An extra CSS class name for the component.
|
|
88
95
|
*/
|
|
@@ -104,6 +111,7 @@ const Layout = ({
|
|
|
104
111
|
topNavRight: topNavRightComponentOrNode,
|
|
105
112
|
sideNav: sideNavComponentOrNode,
|
|
106
113
|
main: mainComponentOrNode,
|
|
114
|
+
footer: footerComponentOrNode,
|
|
107
115
|
className,
|
|
108
116
|
}: Parameters<typeof App>[0]) => {
|
|
109
117
|
const sessionStoreIsReady = useSessionStoreIsReady();
|
|
@@ -124,8 +132,10 @@ const Layout = ({
|
|
|
124
132
|
topNavRightComponentOrNode,
|
|
125
133
|
sideNavComponentOrNode,
|
|
126
134
|
mainComponentOrNode,
|
|
135
|
+
footerComponentOrNode,
|
|
127
136
|
].some((componentOrNode) => componentOrNode);
|
|
128
137
|
const hasSideNav = sideNavComponentOrNode != null;
|
|
138
|
+
const hasFooter = footerComponentOrNode != null;
|
|
129
139
|
|
|
130
140
|
return sessionStoreIsReady && routeStoreIsReady && localStoreIsReady ? (
|
|
131
141
|
<div
|
|
@@ -169,9 +179,20 @@ const Layout = ({
|
|
|
169
179
|
</nav>
|
|
170
180
|
) : null}
|
|
171
181
|
</header>
|
|
172
|
-
<main
|
|
182
|
+
<main
|
|
183
|
+
className={classNames(
|
|
184
|
+
main,
|
|
185
|
+
hasSideNav && mainHasSideNav,
|
|
186
|
+
hasFooter && mainHasFooter,
|
|
187
|
+
)}
|
|
188
|
+
>
|
|
173
189
|
{renderComponentOrNode(mainComponentOrNode)}
|
|
174
190
|
</main>
|
|
191
|
+
{hasFooter ? (
|
|
192
|
+
<footer className={footer}>
|
|
193
|
+
{renderComponentOrNode(footerComponentOrNode)}
|
|
194
|
+
</footer>
|
|
195
|
+
) : null}
|
|
175
196
|
</>
|
|
176
197
|
) : null}
|
|
177
198
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {ComponentType, ReactNode
|
|
2
|
-
import {
|
|
1
|
+
import type {ComponentType, ReactNode} from 'react';
|
|
2
|
+
import {useCallback} from 'react';
|
|
3
3
|
import {classNames, renderComponentOrNode} from '../../common/functions.tsx';
|
|
4
4
|
import {iconSize} from '../../css/dimensions.css.ts';
|
|
5
5
|
import {
|
|
@@ -103,104 +103,101 @@ import {
|
|
|
103
103
|
* 'current'.
|
|
104
104
|
* @icon Lucide.RectangleHorizontal
|
|
105
105
|
*/
|
|
106
|
-
export const Button =
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
[href],
|
|
177
|
-
);
|
|
106
|
+
export const Button = ({
|
|
107
|
+
icon: Icon,
|
|
108
|
+
title: titleComponentOrNode,
|
|
109
|
+
titleRight: titleRightComponentOrNode,
|
|
110
|
+
iconRight: IconRight,
|
|
111
|
+
onClick,
|
|
112
|
+
variant = 'default',
|
|
113
|
+
current,
|
|
114
|
+
href,
|
|
115
|
+
alt,
|
|
116
|
+
className,
|
|
117
|
+
ref,
|
|
118
|
+
}: {
|
|
119
|
+
/**
|
|
120
|
+
* An optional component which renders an icon for the button, and which
|
|
121
|
+
* must accept a className prop.
|
|
122
|
+
*/
|
|
123
|
+
readonly icon?: ComponentType<{className?: string}>;
|
|
124
|
+
/**
|
|
125
|
+
* An optional component, element, or string which renders the title of
|
|
126
|
+
* the button.
|
|
127
|
+
*/
|
|
128
|
+
readonly title?: ComponentType | ReactNode;
|
|
129
|
+
/**
|
|
130
|
+
* An optional component, element, or string which renders a second title
|
|
131
|
+
* on the right side of the button.
|
|
132
|
+
*/
|
|
133
|
+
readonly titleRight?: ComponentType | ReactNode;
|
|
134
|
+
/**
|
|
135
|
+
* An optional component which renders a second icon for the button, and
|
|
136
|
+
* which must accept a className prop.
|
|
137
|
+
*/
|
|
138
|
+
readonly iconRight?: ComponentType<{className?: string}>;
|
|
139
|
+
/**
|
|
140
|
+
* A handler called when the user clicks on the button.
|
|
141
|
+
*/
|
|
142
|
+
readonly onClick?: () => void;
|
|
143
|
+
/**
|
|
144
|
+
* A variant of the button, one of:
|
|
145
|
+
* - `default`
|
|
146
|
+
* - `icon`
|
|
147
|
+
* - `accent`
|
|
148
|
+
* - `ghost`
|
|
149
|
+
* - `item`
|
|
150
|
+
*/
|
|
151
|
+
readonly variant?: keyof typeof buttonVariants;
|
|
152
|
+
/**
|
|
153
|
+
* A flag that indicates that an `item` button is 'current' and therefore
|
|
154
|
+
* highlighted.
|
|
155
|
+
*/
|
|
156
|
+
readonly current?: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* A URL that can be used instead of an `onClick` to launch a new web
|
|
159
|
+
* page, much like a link.
|
|
160
|
+
*/
|
|
161
|
+
readonly href?: string;
|
|
162
|
+
/**
|
|
163
|
+
* Alternative text shown when the user hovers over the button.
|
|
164
|
+
*/
|
|
165
|
+
readonly alt?: string;
|
|
166
|
+
/**
|
|
167
|
+
* An extra CSS class name for the component.
|
|
168
|
+
*/
|
|
169
|
+
readonly className?: string;
|
|
170
|
+
ref?: React.RefObject<HTMLButtonElement>;
|
|
171
|
+
}) => {
|
|
172
|
+
const hrefClick = useCallback(
|
|
173
|
+
() => (href ? open(href, '_blank', 'noreferrer') : null),
|
|
174
|
+
[href],
|
|
175
|
+
);
|
|
178
176
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
);
|
|
177
|
+
return (
|
|
178
|
+
<button
|
|
179
|
+
className={classNames(
|
|
180
|
+
button,
|
|
181
|
+
buttonVariants[variant],
|
|
182
|
+
current && currentStyle,
|
|
183
|
+
className,
|
|
184
|
+
)}
|
|
185
|
+
onClick={onClick ?? hrefClick}
|
|
186
|
+
title={alt}
|
|
187
|
+
ref={ref}
|
|
188
|
+
>
|
|
189
|
+
{Icon ? <Icon className={iconSize} /> : null}
|
|
190
|
+
{titleComponentOrNode ? (
|
|
191
|
+
<span className={titleStyle}>
|
|
192
|
+
{renderComponentOrNode(titleComponentOrNode)}
|
|
193
|
+
</span>
|
|
194
|
+
) : null}
|
|
195
|
+
{titleRightComponentOrNode ? (
|
|
196
|
+
<span className={titleStyleRight}>
|
|
197
|
+
{renderComponentOrNode(titleRightComponentOrNode)}
|
|
198
|
+
</span>
|
|
199
|
+
) : null}
|
|
200
|
+
{IconRight ? <IconRight className={iconSize} /> : null}
|
|
201
|
+
</button>
|
|
202
|
+
);
|
|
203
|
+
};
|
|
@@ -8,6 +8,7 @@ const classAndObject = createTheme({
|
|
|
8
8
|
radius: fallbackVar('var(--tinyWidgets-radius)', '0.5rem'),
|
|
9
9
|
sideNavWidth: fallbackVar('var(--tinyWidgets-sideNavWidth)', '20rem'),
|
|
10
10
|
topNavHeight: fallbackVar('var(--tinyWidgets-topNavHeight)', '4rem'),
|
|
11
|
+
footerHeight: fallbackVar('var(--tinyWidgets-footerHeight)', '2rem'),
|
|
11
12
|
});
|
|
12
13
|
export const dimensionsClass = classAndObject[0];
|
|
13
14
|
|
|
@@ -24,6 +25,7 @@ export const dimensionsClass = classAndObject[0];
|
|
|
24
25
|
* - `radius`
|
|
25
26
|
* - `sideNavWidth`
|
|
26
27
|
* - `topNavHeight`
|
|
28
|
+
* - `footerHeight`
|
|
27
29
|
*
|
|
28
30
|
* You can use these variables directly in React components that take style
|
|
29
31
|
* attributes, like this:
|
package/src/index.ts
CHANGED
|
@@ -10,13 +10,7 @@ export {Metric} from './components/Metric/index.tsx';
|
|
|
10
10
|
export {Row} from './components/Row/index.tsx';
|
|
11
11
|
export {Summary} from './components/Summary/index.tsx';
|
|
12
12
|
export {Tag} from './components/Tag/index.tsx';
|
|
13
|
-
export {
|
|
14
|
-
TasksProvider,
|
|
15
|
-
useScheduleTask,
|
|
16
|
-
} from './components/TasksProvider/index.tsx';
|
|
17
13
|
|
|
18
14
|
export {classNames} from './common/functions.tsx';
|
|
19
15
|
export {useDark} from './stores/LocalStore.tsx';
|
|
20
16
|
export {useRoute, useSetRouteCallback} from './stores/RouteStore.tsx';
|
|
21
|
-
|
|
22
|
-
export type {ScheduleTask} from './components/TasksProvider/index.tsx';
|
package/.prettierignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
package.json
|
package/bun.lockb
DELETED
|
Binary file
|