@typed-grid-areas/solid 0.0.0 → 0.1.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/LICENSE +21 -0
- package/README.md +1402 -0
- package/dist/gridComponent.d.ts +80 -0
- package/dist/gridComponent.jsx +143 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +145 -0
- package/dist/index.jsx +1 -0
- package/package.json +58 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ComponentProps, JSX, ValidComponent } from "solid-js";
|
|
2
|
+
import type { GridConfig } from "typed-grid-areas";
|
|
3
|
+
/**
|
|
4
|
+
* Props of a slot component (`<Card.icon>`) and of a grid's root component
|
|
5
|
+
* (`<Card>`): anything the element `as` renders takes (a `div`'s by
|
|
6
|
+
* default), plus `as`.
|
|
7
|
+
*/
|
|
8
|
+
export type SlotComponentProps<T extends ValidComponent = "div"> = Omit<ComponentProps<T>, "as"> & {
|
|
9
|
+
/**
|
|
10
|
+
* The element to render as the slot (or grid) instead of a `div`: a tag
|
|
11
|
+
* name (`"label"`), a component, or a render function
|
|
12
|
+
* (`props => <label {...props} />`). A component or render function gets
|
|
13
|
+
* the slot's props, including its `data-area`, and must spread them onto
|
|
14
|
+
* its root element.
|
|
15
|
+
*/
|
|
16
|
+
as?: T | SlotRenderFunction;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* A render function passed to `as`: it gets the slot's props, including its
|
|
20
|
+
* `data-area`, to spread onto the element it renders. Annotate its `props`
|
|
21
|
+
* (`(props: JSX.LabelHTMLAttributes<HTMLLabelElement>) => …`) for the slot
|
|
22
|
+
* to take that element's attributes rather than a `div`'s.
|
|
23
|
+
*/
|
|
24
|
+
export type SlotRenderFunction = (props: JSX.HTMLAttributes<any>) => JSX.Element;
|
|
25
|
+
/** The props of a grid's root component (`<Card>`). */
|
|
26
|
+
export type GridComponentProps<T extends ValidComponent = "div"> = SlotComponentProps<T>;
|
|
27
|
+
/** A slot component (`<Card.icon>`): renders the element that fills one area. */
|
|
28
|
+
export type SlotComponent = <T extends ValidComponent = "div">(props: SlotComponentProps<T>) => JSX.Element;
|
|
29
|
+
/**
|
|
30
|
+
* The component a definition renders as: the grid itself, with a slot
|
|
31
|
+
* component per area as a member, named exactly like the area. An area
|
|
32
|
+
* nested through `nest` is the root component of the nested grid instead,
|
|
33
|
+
* with that grid's slots as its members (`<Card.content.icon>`).
|
|
34
|
+
*/
|
|
35
|
+
export type GridComponent<TAreaName extends string, TNest = {}> = (<T extends ValidComponent = "div">(props: GridComponentProps<T>) => JSX.Element) & {
|
|
36
|
+
readonly [K in TAreaName]: K extends keyof TNest ? TNest[K] : SlotComponent;
|
|
37
|
+
};
|
|
38
|
+
/** Any grid component, whatever its areas. */
|
|
39
|
+
type AnyGridComponent = GridComponent<any, any>;
|
|
40
|
+
/** Options of `createGridComponent`. */
|
|
41
|
+
export type GridComponentOptions<TAreaName extends string> = {
|
|
42
|
+
/**
|
|
43
|
+
* Grids nested into areas of this one: `nest: { content: ContentGrid }`
|
|
44
|
+
* makes `<Card.content>` both the `content` slot and the root of
|
|
45
|
+
* `ContentGrid`.
|
|
46
|
+
*/
|
|
47
|
+
nest?: {
|
|
48
|
+
readonly [K in TAreaName]?: AnyGridComponent;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Turns a definition into the component it renders as.
|
|
53
|
+
*
|
|
54
|
+
* `<Card>` renders the grid (inside its own size container when the
|
|
55
|
+
* definition has breakpoints) and puts the definition's CSS on the page;
|
|
56
|
+
* `<Card.icon>` renders the slot that fills the `icon` area. Slots accept
|
|
57
|
+
* `class`, `style`, `children`, regular element props, and `as` to render
|
|
58
|
+
* your own element as the slot.
|
|
59
|
+
*
|
|
60
|
+
* Create grid components at module level, once per definition.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* const Card = createGridComponent(
|
|
65
|
+
* defineLayout({ areas: ["input?", "content"], layouts: [{ template: "input content" }] }),
|
|
66
|
+
* { nest: { content: ContentGrid } },
|
|
67
|
+
* );
|
|
68
|
+
*
|
|
69
|
+
* <Card>
|
|
70
|
+
* <Card.input as="label" for="notify">…</Card.input>
|
|
71
|
+
* <Card.content>
|
|
72
|
+
* <Card.content.icon>…</Card.content.icon>
|
|
73
|
+
* </Card.content>
|
|
74
|
+
* </Card>
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function createGridComponent<TAreaName extends string, const TNest extends GridComponentOptions<TAreaName>["nest"] = {}>(definition: GridConfig<TAreaName>, options?: {
|
|
78
|
+
nest?: TNest;
|
|
79
|
+
}): GridComponent<TAreaName, TNest>;
|
|
80
|
+
export {};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { children, createEffect, mergeProps, sharedConfig, splitProps, } from "solid-js";
|
|
2
|
+
import { Dynamic, isServer, ssr, useAssets } from "solid-js/web";
|
|
3
|
+
import { createSlotCheck, gridMarkup, gridStyleTags, insertGridStyle, } from "typed-grid-areas/adapter";
|
|
4
|
+
/**
|
|
5
|
+
* What a server render has registered with `useAssets`, by render. The
|
|
6
|
+
* render's list of assets is internal to Solid; it's only used here as a
|
|
7
|
+
* key that's new for each render.
|
|
8
|
+
*/
|
|
9
|
+
const registeredStyles = new WeakMap();
|
|
10
|
+
/**
|
|
11
|
+
* Puts a definition's CSS on the page: on the server, its style tag among
|
|
12
|
+
* the render's assets (once per render), which Solid injects before
|
|
13
|
+
* `</head>`; in the browser, its style tag in `<head>`, reusing one the
|
|
14
|
+
* server rendered.
|
|
15
|
+
*/
|
|
16
|
+
function emitCss(definition) {
|
|
17
|
+
if (!isServer) {
|
|
18
|
+
insertGridStyle(document, definition);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const assets = sharedConfig.context?.assets;
|
|
22
|
+
if (assets === undefined) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const registered = registeredStyles.get(assets) ?? new Set();
|
|
26
|
+
registeredStyles.set(assets, registered);
|
|
27
|
+
const { id } = gridMarkup(definition);
|
|
28
|
+
if (registered.has(id)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
registered.add(id);
|
|
32
|
+
// `ssr` marks the tag's HTML as already rendered, so it isn't escaped.
|
|
33
|
+
useAssets(() => ssr(gridStyleTags([definition])));
|
|
34
|
+
}
|
|
35
|
+
function createRoot(definition) {
|
|
36
|
+
const markup = gridMarkup(definition);
|
|
37
|
+
return function Root(props) {
|
|
38
|
+
emitCss(definition);
|
|
39
|
+
const [local, others] = splitProps(props, ["as", "ref", "children", "data-area"]);
|
|
40
|
+
const { sizeContainer, grid: gridElement } = markup.elements(local["data-area"]);
|
|
41
|
+
const resolved = children(() => local.children);
|
|
42
|
+
let grid;
|
|
43
|
+
const ref = (element) => {
|
|
44
|
+
grid = element;
|
|
45
|
+
local.ref?.(element);
|
|
46
|
+
};
|
|
47
|
+
// In development, check the slots after mount and whenever they change. Written out,
|
|
48
|
+
// not `isDevelopment()`, so production builds drop the check.
|
|
49
|
+
try {
|
|
50
|
+
if (process.env.NODE_ENV === "development") {
|
|
51
|
+
if (!isServer) {
|
|
52
|
+
const checkSlots = createSlotCheck(definition, {
|
|
53
|
+
strayChildRemedy: "make it a slot with `as`",
|
|
54
|
+
});
|
|
55
|
+
createEffect(() => {
|
|
56
|
+
resolved();
|
|
57
|
+
if (grid !== undefined) {
|
|
58
|
+
for (const warning of checkSlots(grid)) {
|
|
59
|
+
// eslint-disable-next-line no-console
|
|
60
|
+
console.warn(warning);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
// Without a bundler, `process` may not exist: then this isn't development.
|
|
69
|
+
if (!(error instanceof ReferenceError)) {
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const element = (<Dynamic component={local.as ?? "div"} {...others} {...gridElement.attributes} ref={ref}>
|
|
74
|
+
{resolved()}
|
|
75
|
+
</Dynamic>);
|
|
76
|
+
if (sizeContainer === undefined) {
|
|
77
|
+
return element;
|
|
78
|
+
}
|
|
79
|
+
return (<div {...sizeContainer.attributes} style={sizeContainer.styleText}>
|
|
80
|
+
{element}
|
|
81
|
+
</div>);
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function createSlotComponent(area) {
|
|
85
|
+
return function SlotComponent(props) {
|
|
86
|
+
const [local, others] = splitProps(props, ["as"]);
|
|
87
|
+
return <Dynamic component={local.as ?? "div"} {...others} data-area={area}/>;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Defines `members` on a component. `defineProperty`, because an area may be
|
|
92
|
+
* named like a function's own read-only properties (`name`, `length`).
|
|
93
|
+
*/
|
|
94
|
+
function withMembers(component, members) {
|
|
95
|
+
for (const [key, value] of Object.entries(members)) {
|
|
96
|
+
Object.defineProperty(component, key, { value, enumerable: true, configurable: true });
|
|
97
|
+
}
|
|
98
|
+
return component;
|
|
99
|
+
}
|
|
100
|
+
/** The members of a grid component, one per area. */
|
|
101
|
+
function membersOf(component) {
|
|
102
|
+
return Object.fromEntries(Object.entries(component));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Turns a definition into the component it renders as.
|
|
106
|
+
*
|
|
107
|
+
* `<Card>` renders the grid (inside its own size container when the
|
|
108
|
+
* definition has breakpoints) and puts the definition's CSS on the page;
|
|
109
|
+
* `<Card.icon>` renders the slot that fills the `icon` area. Slots accept
|
|
110
|
+
* `class`, `style`, `children`, regular element props, and `as` to render
|
|
111
|
+
* your own element as the slot.
|
|
112
|
+
*
|
|
113
|
+
* Create grid components at module level, once per definition.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```tsx
|
|
117
|
+
* const Card = createGridComponent(
|
|
118
|
+
* defineLayout({ areas: ["input?", "content"], layouts: [{ template: "input content" }] }),
|
|
119
|
+
* { nest: { content: ContentGrid } },
|
|
120
|
+
* );
|
|
121
|
+
*
|
|
122
|
+
* <Card>
|
|
123
|
+
* <Card.input as="label" for="notify">…</Card.input>
|
|
124
|
+
* <Card.content>
|
|
125
|
+
* <Card.content.icon>…</Card.content.icon>
|
|
126
|
+
* </Card.content>
|
|
127
|
+
* </Card>
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export function createGridComponent(definition, options = {}) {
|
|
131
|
+
const members = {};
|
|
132
|
+
for (const area of definition.areas) {
|
|
133
|
+
const nested = options.nest?.[area];
|
|
134
|
+
if (nested === undefined) {
|
|
135
|
+
members[area] = createSlotComponent(area);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const Nested = nested;
|
|
139
|
+
const NestedRoot = (props) => (<Nested {...mergeProps(props, { "data-area": area })}/>);
|
|
140
|
+
members[area] = withMembers(NestedRoot, membersOf(nested));
|
|
141
|
+
}
|
|
142
|
+
return withMembers(createRoot(definition), members);
|
|
143
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createGridComponent, type GridComponent, type GridComponentOptions, type GridComponentProps, type SlotComponent, type SlotComponentProps, type SlotRenderFunction, } from "./gridComponent.tsx";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { Dynamic, createComponent, insert, isServer, mergeProps, spread, ssr, template, useAssets } from "solid-js/web";
|
|
2
|
+
import { children, createEffect, mergeProps as mergeProps$1, sharedConfig, splitProps } from "solid-js";
|
|
3
|
+
import { createSlotCheck, gridMarkup, gridStyleTags, insertGridStyle } from "typed-grid-areas/adapter";
|
|
4
|
+
// src/gridComponent.tsx
|
|
5
|
+
var _tmpl$ = /*#__PURE__*/ template(`<div>`);
|
|
6
|
+
/**
|
|
7
|
+
* What a server render has registered with `useAssets`, by render. The
|
|
8
|
+
* render's list of assets is internal to Solid; it's only used here as a
|
|
9
|
+
* key that's new for each render.
|
|
10
|
+
*/
|
|
11
|
+
var registeredStyles = /* @__PURE__ */ new WeakMap();
|
|
12
|
+
/**
|
|
13
|
+
* Puts a definition's CSS on the page: on the server, its style tag among
|
|
14
|
+
* the render's assets (once per render), which Solid injects before
|
|
15
|
+
* `</head>`; in the browser, its style tag in `<head>`, reusing one the
|
|
16
|
+
* server rendered.
|
|
17
|
+
*/
|
|
18
|
+
function emitCss(definition) {
|
|
19
|
+
if (!isServer) {
|
|
20
|
+
insertGridStyle(document, definition);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const assets = sharedConfig.context?.assets;
|
|
24
|
+
if (assets === void 0) return;
|
|
25
|
+
const registered = registeredStyles.get(assets) ?? /* @__PURE__ */ new Set();
|
|
26
|
+
registeredStyles.set(assets, registered);
|
|
27
|
+
const { id } = gridMarkup(definition);
|
|
28
|
+
if (registered.has(id)) return;
|
|
29
|
+
registered.add(id);
|
|
30
|
+
useAssets(() => ssr(gridStyleTags([definition])));
|
|
31
|
+
}
|
|
32
|
+
function createRoot(definition) {
|
|
33
|
+
const markup = gridMarkup(definition);
|
|
34
|
+
return function Root(props) {
|
|
35
|
+
emitCss(definition);
|
|
36
|
+
const [local, others] = splitProps(props, [
|
|
37
|
+
"as",
|
|
38
|
+
"ref",
|
|
39
|
+
"children",
|
|
40
|
+
"data-area"
|
|
41
|
+
]);
|
|
42
|
+
const { sizeContainer, grid: gridElement } = markup.elements(local["data-area"]);
|
|
43
|
+
const resolved = children(() => local.children);
|
|
44
|
+
let grid;
|
|
45
|
+
const ref = (element) => {
|
|
46
|
+
grid = element;
|
|
47
|
+
local.ref?.(element);
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
if (process.env.NODE_ENV === "development") {
|
|
51
|
+
if (!isServer) {
|
|
52
|
+
const checkSlots = createSlotCheck(definition, { strayChildRemedy: "make it a slot with `as`" });
|
|
53
|
+
createEffect(() => {
|
|
54
|
+
resolved();
|
|
55
|
+
if (grid !== void 0) for (const warning of checkSlots(grid)) console.warn(warning);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (!(error instanceof ReferenceError)) throw error;
|
|
61
|
+
}
|
|
62
|
+
const element = createComponent(Dynamic, mergeProps({ get component() {
|
|
63
|
+
return local.as ?? "div";
|
|
64
|
+
} }, others, () => gridElement.attributes, {
|
|
65
|
+
ref,
|
|
66
|
+
get children() {
|
|
67
|
+
return resolved();
|
|
68
|
+
}
|
|
69
|
+
}));
|
|
70
|
+
if (sizeContainer === void 0) return element;
|
|
71
|
+
return (() => {
|
|
72
|
+
var _el$ = _tmpl$();
|
|
73
|
+
spread(_el$, mergeProps(() => sizeContainer.attributes, { get style() {
|
|
74
|
+
return sizeContainer.styleText;
|
|
75
|
+
} }), false, true);
|
|
76
|
+
insert(_el$, element);
|
|
77
|
+
return _el$;
|
|
78
|
+
})();
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function createSlotComponent(area) {
|
|
82
|
+
return function SlotComponent(props) {
|
|
83
|
+
const [local, others] = splitProps(props, ["as"]);
|
|
84
|
+
return createComponent(Dynamic, mergeProps({ get component() {
|
|
85
|
+
return local.as ?? "div";
|
|
86
|
+
} }, others, { "data-area": area }));
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Defines `members` on a component. `defineProperty`, because an area may be
|
|
91
|
+
* named like a function's own read-only properties (`name`, `length`).
|
|
92
|
+
*/
|
|
93
|
+
function withMembers(component, members) {
|
|
94
|
+
for (const [key, value] of Object.entries(members)) Object.defineProperty(component, key, {
|
|
95
|
+
value,
|
|
96
|
+
enumerable: true,
|
|
97
|
+
configurable: true
|
|
98
|
+
});
|
|
99
|
+
return component;
|
|
100
|
+
}
|
|
101
|
+
/** The members of a grid component, one per area. */
|
|
102
|
+
function membersOf(component) {
|
|
103
|
+
return Object.fromEntries(Object.entries(component));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Turns a definition into the component it renders as.
|
|
107
|
+
*
|
|
108
|
+
* `<Card>` renders the grid (inside its own size container when the
|
|
109
|
+
* definition has breakpoints) and puts the definition's CSS on the page;
|
|
110
|
+
* `<Card.icon>` renders the slot that fills the `icon` area. Slots accept
|
|
111
|
+
* `class`, `style`, `children`, regular element props, and `as` to render
|
|
112
|
+
* your own element as the slot.
|
|
113
|
+
*
|
|
114
|
+
* Create grid components at module level, once per definition.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```tsx
|
|
118
|
+
* const Card = createGridComponent(
|
|
119
|
+
* defineLayout({ areas: ["input?", "content"], layouts: [{ template: "input content" }] }),
|
|
120
|
+
* { nest: { content: ContentGrid } },
|
|
121
|
+
* );
|
|
122
|
+
*
|
|
123
|
+
* <Card>
|
|
124
|
+
* <Card.input as="label" for="notify">…</Card.input>
|
|
125
|
+
* <Card.content>
|
|
126
|
+
* <Card.content.icon>…</Card.content.icon>
|
|
127
|
+
* </Card.content>
|
|
128
|
+
* </Card>
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
function createGridComponent(definition, options = {}) {
|
|
132
|
+
const members = {};
|
|
133
|
+
for (const area of definition.areas) {
|
|
134
|
+
const nested = options.nest?.[area];
|
|
135
|
+
if (nested === void 0) {
|
|
136
|
+
members[area] = createSlotComponent(area);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const Nested = nested;
|
|
140
|
+
const NestedRoot = (props) => createComponent(Nested, mergeProps(() => mergeProps$1(props, { "data-area": area })));
|
|
141
|
+
members[area] = withMembers(NestedRoot, membersOf(nested));
|
|
142
|
+
}
|
|
143
|
+
return withMembers(createRoot(definition), members);
|
|
144
|
+
}
|
|
145
|
+
export { createGridComponent };
|
package/dist/index.jsx
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createGridComponent, } from "./gridComponent.jsx";
|
package/package.json
CHANGED
|
@@ -1 +1,58 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "@typed-grid-areas/solid",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Solid adapter for typed-grid-areas: render a grid definition as typed slot components.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"css-grid",
|
|
7
|
+
"grid-template-areas",
|
|
8
|
+
"layout",
|
|
9
|
+
"typescript",
|
|
10
|
+
"solid"
|
|
11
|
+
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/MichaelBuss/typed-grid-areas.git",
|
|
17
|
+
"directory": "packages/solid"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://michaelbuss.github.io/typed-grid-areas/",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/MichaelBuss/typed-grid-areas/issues"
|
|
22
|
+
},
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"solid": "./dist/index.jsx",
|
|
27
|
+
"import": "./dist/index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "vite build && tsc -p tsconfig.build.json",
|
|
35
|
+
"prepack": "npm run build && cp ../../README.md ../../LICENSE .",
|
|
36
|
+
"postpack": "rm README.md LICENSE",
|
|
37
|
+
"test": "vitest run --project unit --project node",
|
|
38
|
+
"test:browser": "vitest run --project browser --project browser-development",
|
|
39
|
+
"typecheck": "tsc --noEmit"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"solid-js": "^1.9.0"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"typed-grid-areas": "^0.3.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@typed-grid-areas/acceptance": "*",
|
|
49
|
+
"@types/node": "^22.20.5",
|
|
50
|
+
"@vitest/browser-playwright": "^5.0.1",
|
|
51
|
+
"playwright": "^1.64.1",
|
|
52
|
+
"solid-js": "^1.9.17",
|
|
53
|
+
"typescript": "^7.0.2",
|
|
54
|
+
"vite": "^8.3.5",
|
|
55
|
+
"vite-plugin-solid": "^2.11.14",
|
|
56
|
+
"vitest": "^5.0.1"
|
|
57
|
+
}
|
|
58
|
+
}
|