From 063c90750c9b469f0e174c50d091e4e9b816ec00 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 21 Sep 2023 22:41:25 +0900 Subject: [PATCH] refactor: add inline style helper --- package.json | 1 + packages/tiny-toast/src/preact/ui.tsx | 55 ++++++++++++++++++++++----- pnpm-lock.yaml | 19 +++++---- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 687450c3..606ae956 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@unocss/preset-uno": "^0.55.7", "@unocss/reset": "^0.55.7", "@vitejs/plugin-react": "^3.1.0", + "csstype": "^3.1.2", "esbuild": "^0.19.3", "esbuild-register": "^3.5.0", "happy-dom": "^11.2.0", diff --git a/packages/tiny-toast/src/preact/ui.tsx b/packages/tiny-toast/src/preact/ui.tsx index f3c8fe0d..c3f46bea 100644 --- a/packages/tiny-toast/src/preact/ui.tsx +++ b/packages/tiny-toast/src/preact/ui.tsx @@ -1,11 +1,10 @@ import { TransitionManager } from "@hiogawa/tiny-transition"; +import type * as CSS from "csstype"; import { h } from "preact"; import { useEffect, useReducer, useState } from "preact/hooks"; import { TOAST_STEP } from "../core"; import type { PreactToastItem, PreactToastManager } from "./api"; -// TODO: rewrite with inline style instead of unocss class - export function ToastContainer({ toast }: { toast: PreactToastManager }) { useSubscribe(toast.subscribe); @@ -13,7 +12,12 @@ export function ToastContainer({ toast }: { toast: PreactToastManager }) { return h( "div", { - class: "fixed inset-0 z-9999 pointer-events-none", + style: istyle({ + position: "fixed", + inset: 0, + zIndex: 9999, + pointerEvents: "none", + }), onMouseEnter: () => { toast.pause(true); }, @@ -25,7 +29,14 @@ export function ToastContainer({ toast }: { toast: PreactToastManager }) { h( "div", { - class: "absolute top-3 flex flex-col-reverse items-center w-full", + style: istyle({ + position: "absolute", + top: "3px", + width: "100%", + display: "flex", + flexDirection: "column-reverse", + alignItems: "center", + }), }, toast.items.map((item) => h(ToastAnimation, { key: item.id, toast, item }) @@ -82,7 +93,10 @@ function ToastAnimation({ "div", { ref: manager.setElement, - class: "duration-200 transform pointer-events-auto", + style: istyle({ + transitionDuration: "200ms", + pointerEvents: "auto", + }), }, h("div", { class: "py-1" }, h(ToastItemComponent, { toast, item })) ); @@ -109,16 +123,27 @@ function ToastItemComponent({ return h( "div", { - class: item.data.class ?? "rounded-lg shadow-lg", - style: item.data.style, + class: item.data.class, + style: + item.data.style ?? + istyle({ + borderRadius: "8px", + boxShadow: + "0 3px 10px rgba(0, 0, 0, 0.1), 0 3px 3px rgba(0, 0, 0, 0.05)", + }), }, [ h( "div", { - class: "flex items-center p-2", + style: istyle({ + display: "flex", + alignItems: "center", + padding: "0.5rem", + }), }, [ + // TODO: inline icon item.data.type === "success" && h("span", { class: "i-ri-checkbox-circle-fill text-green text-2xl", @@ -131,7 +156,11 @@ function ToastItemComponent({ h("span", { class: "i-ri-information-line text-blue text-2xl", }), - h("div", { class: "px-2" }, item.data.render({ h, toast, item })), + h( + "div", + { style: istyle({ padding: "0 0.5rem" }) }, + item.data.render({ h, toast, item }) + ), ] ), ] @@ -159,3 +188,11 @@ function collapse(el: HTMLElement) { function resetCollapse(el: HTMLElement) { el.style.height = ""; } + +// type-safe inline style util based on csstype +// cf. https://github.com/cristianbote/goober/blob/a849b2d644146d96fa1dd1c560f6418ee1e1c469/src/core/parse.js#L48 +function istyle(props: CSS.Properties): string { + return Object.entries(props) + .map(([k, v]) => `${k.replace(/[A-Z]/g, "-$&").toLowerCase()}:${v}`) + .join(";"); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 02719cbf..3c7bc45e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: '@vitejs/plugin-react': specifier: ^3.1.0 version: 3.1.0(vite@4.4.9) + csstype: + specifier: ^3.1.2 + version: 3.1.2 esbuild: specifier: ^0.19.3 version: 0.19.3 @@ -272,7 +275,7 @@ packages: '@emotion/hash': 0.8.0 '@emotion/unitless': 0.7.5 classnames: 2.3.2 - csstype: 3.1.1 + csstype: 3.1.2 rc-util: 5.27.2(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -1248,7 +1251,7 @@ packages: '@emotion/memoize': 0.8.0 '@emotion/unitless': 0.8.0 '@emotion/utils': 1.2.0 - csstype: 3.1.1 + csstype: 3.1.2 dev: false /@emotion/sheet@1.2.1: @@ -2199,7 +2202,7 @@ packages: dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 - csstype: 3.1.1 + csstype: 3.1.2 dev: true /@types/react@18.2.21: @@ -2207,7 +2210,7 @@ packages: dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 - csstype: 3.1.1 + csstype: 3.1.2 /@types/scheduler@0.16.2: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} @@ -3144,8 +3147,8 @@ packages: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} dev: true - /csstype@3.1.1: - resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} /csv-generate@3.4.3: resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==} @@ -3303,7 +3306,7 @@ packages: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} dependencies: '@babel/runtime': 7.20.13 - csstype: 3.1.1 + csstype: 3.1.2 dev: false /duplexer@0.1.2: @@ -5767,7 +5770,7 @@ packages: /solid-js@1.7.6: resolution: {integrity: sha512-DXVOTjUh/bIAhE0fIqu3ezGLyQaez7v8EOw3uPLIi87DmLjg+hsuCAgKyNIZ+o4jUetOk3ZORccvJmE1yZUk8g==} dependencies: - csstype: 3.1.1 + csstype: 3.1.2 seroval: 0.5.1 /solid-refresh@0.5.2(solid-js@1.7.6):