atellmer / dark Goto Github PK
View Code? Open in Web Editor NEWThe lightweight and powerful UI rendering engine without dependencies and written in TypeScript💫 (Browser, Node.js, Android, iOS, Windows, Linux, macOS)
License: MIT License
The lightweight and powerful UI rendering engine without dependencies and written in TypeScript💫 (Browser, Node.js, Android, iOS, Windows, Linux, macOS)
License: MIT License
I have run into the situation where I am getting no application rendering, at the same time I am also not getting any error message.
This has happened while attempting to use the TranslationsProvider
component exported by dark-translator, you can see the setup here.
It appears that the TranslationsProvider
component doesn't run at all, a simple console.log()
at the top of the component doesn't output anything.
How would you debug this? Do you have a guess on what the problem may be?
Dark's SynthethicEvent doesn't seem to have a currentTarget property. Is this a design choice?
In text inputs, the value
prop doesn't seem to be respected.
The input HTML attribute value matches the variable in the component state, however the rendered value can differ.
It is a problem particularly when validating user input: invalid values are caught and corrected at the component state level, but displayed value does not match the component state.
This becomes even more of a problem when attempting to utilize event.target.selectionStart
when the displayed value contains more characters than the state variable
This is a minimal repro although this repro is not particularly refined. I am working on a much larger component at the moment to handle currency input, this behavior blocks me.
Is there a way to delay useSpring animations?
I see there is a delay property on SpringApi, but I don't understand if that is what I want nor how to use it correctly
Do you know why using css fragments in GlobalStyle does not seem to work (neither server nor browser)?
const typography = () => css`
body {
text-rendering: optimizeLegibility;
color: ${props => props.theme.black};
line-height: 1.5;
}
`
const GlobalStyle = createGlobalStyle`
body {
margin: 0;
min-height: 100%;
background-color: ${props => props.theme.white};
overflow-y: hidden;
}
#dark-root {
isolation: isolate;
}
/* ${typography} breaks everything */
${() => typography} /* does not break everything but doesn't render anything either */
/* ${() => typography()} breaks everything */
`
const lightColors = {
white: '#f6f2ef',
black: '#1e1f1f',
}
const light = {
...lightColors,
borderStyle: `solid 1px ${lightColors.black}`
}
const Theme = component(({ slot }) => {
const [theme, setTheme] = useState(light)
return (
<ThemeProvider theme={theme}>
<GlobalStyle />
{slot}
</ThemeProvider>
)
})
const Root = component(({ slot }) => {
return <Theme><GlobalStyle />{slot}</Theme>
}
Update: I have since noticed that ${() => typography()}
does render the styles, but everything breaks nonetheless, I will investigate more (error: RangeError: Maximum call stack size exceeded.)
I have an internationalized application, paths are prefixed with the current language.
I would like to redirect the visitor using the data contained in the path, as you can see in this component here.
How would I do that?
I think the information that most closely describes the Dark web-router API, that I can find, is this one here, is this how?
Raw json is automatically escaped during rendering.
What is the recommended technique to insert json in a script tag? It is necessary for json+ld
I am looking for an equivalent to dangerouslySetInnerHTML, something similar to this
I have noticed Dark renders <!--dark:matter-->
whenever a component returns null, is this used by anything?
I only see tests that check for the existence of these comments
I am using a Page
component that has an App
child component.
On the server:
DataClient
is created and given to the App
componentApp
component is renderedDataClient
is then given to the Page
component. This allows the Page
component to use the data needed to render App
, without duplicating logic and without performing the same requests twice.This results in 2 <script type="text/dark-state">
elements being generated in the server response to the browser.
To prevent this, I propose the DataClient should be dehydrated manually.
This is really not that important imo but I have noticed that rules like these aren't minified in the styled output
export const typographyCSS = css`
select,
textarea,
input,
button {
font: inherit;
}
select,
textarea,
input {
letter-spacing: inherit;
word-spacing: inherit;
}
p,
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
overflow-wrap: break-word;
}
`
I expect
button,input,select,textarea{font:inherit}input,select,textarea{letter-spacing:inherit;word-spacing:inherit}h1,h2,h3,h4,h5,h6,p{margin:0;overflow-wrap:break-word}
But styled generates this
select,
textarea,
input,
button{font:inherit;}select,
textarea,
input{letter-spacing:inherit;word-spacing:inherit;}p,
h1,
h2,
h3,
h4,
h5,
h6{margin:0;overflow-wrap:break-word;}
renderToStream
's bootstrapScripts
does not mark scripts with the type="module"
attribute.
In the event that the browser bundle is loaded on the browser via this way, loading routes using the lazy
function will not work, browsers will throw error Uncaught SyntaxError: Cannot use import statement outside a module (at index.js:1:1)
Suggested change: add bootstrapModules
property to RenderToStreamOptions
that accepts an array of string just like bootstrapScripts
except the resulting output would be <script type="module" src="${script}" defer></script>
instead of just <script src="${script}" defer></script>
Example of the issue is demonstrated here
Hi, since the last update I am getting these errors and nothing renders, not even <!-- dark-matter -->
.
This seemed to happen with the slot
of my TranslationsProvider
component.
I have attempted to replicate the issue here with no success.
18222 | };
18223 | var Memo2 = memo6(component12(({ getValue }) => getValue()), (p4, n3) => detectAreDepsDifferent2(p4.deps, n3.deps));
18224 |
18225 | // ../../node_modules/@dark-engine/core/dist/esm/internal/internal.js
18226 | return $$scope2().getCursorFiber();
^
error: TypeError: undefined is not an object (evaluating '$$scope2().getCursorFiber')
at onError (/home/coachonko/website/packages/storefront/build/server/index.js:14701:26)
at /home/coachonko/website/packages/storefront/build/server/index.js:14641:14
at forEach (:1:11)
at emit (/home/coachonko/website/packages/storefront/build/server/index.js:211:63)
at workLoop (/home/coachonko/website/packages/storefront/build/server/index.js:1755:22)
at performWorkUntilDeadline (/home/coachonko/website/packages/storefront/build/server/index.js:1368:47)
at forEach (:1:11)
at emit (/home/coachonko/website/packages/storefront/build/server/index.js:211:63)
at /home/coachonko/website/packages/storefront/build/server/index.js:1243:24
The trace doesn't give me any useful information, all of these lines point to internal functions. For example, the deepest point, 1243:24 point to this
class MessagePort {
channel;
offs = [];
constructor(channel) {
this.channel = channel;
}
on(event, callback) {
const off = this.channel.on(event, callback);
this.offs.push(off);
}
postMessage(value15) {
platform.spawn(() => {
this.channel.emit("message", value15);
});
}
unref() {
this.offs.forEach((x3) => x3());
}
}
How would you find the source of such issue? I am lost
14:36: after further testing I am suspecting the useInView hook, I have also seen I was wrongerror: Error: [@dark-engine/core]: The function was not installed by renderer!
14:52: It was caused by useScrollbarWidth, now investigating why
The following style
import { Link } from '@dark-engine/web-router'
import { styled, css } from '@dark-engine/styled'
const disabledStyle = ({ disabled }) => {
if (disabled) {
return css`
pointer-events: none;
opacity: .2;`
}
return css`
pointer-events: auto;
opacity: 1;`
}
const underlineStyle = ({ underline }) => {
if (underline) {
return css`text-decoration: none;
background-image: linear-gradient(currentColor,currentColor);
background-repeat: no-repeat;
transition: background-size .3s;`
}
}
const activeStyle = ({ active }) => {
if (active) {
return css`
background-position: 0 100%;
background-size: 100% 1px;
@media(hover: hover) {
&:hover {
background-position:100% 100%;
background-size: 0 1px
}
}
@media(hover: none) {
&:active {
background-position:100% 100%;
background-size: 0 1px
}
}`
}
return css`
background-position: 100% 100%;
background-size: 0 1px;
@media(hover: hover) {
&:hover {
background-position:0 100%;
background-size: 100% 1px;
}
}
@media(hover: none) {
&:active {
background-position:0 100%;
background-size: 100% 1px;
}
}`
}
export const button = ({ disabled, underline, active }) => css`
position: relative;
display: inline-flex;
align-items: center;
${disabledStyle({ disabled })}
${underlineStyle({ underline })}
${activeStyle({ active })}`
const StyledLink = styled(Link)`
${({ disabled, active }) => button({ disabled, underline: true, active })}
`
Results into this in the browser
.dk-jeihhc {
position: relative;
display: inline-flex;
align-items: center;
pointer-events: auto;
opacity: 1;
text-decoration: none;
background-image: linear-gradient(currentColor, currentColor);
background-repeat: no-repeat;
transition: background-size .3s;
background-position: 100% 100%;
background-size: 0 1px;
}
@media(hover: hover) {
.dk-jeihhc {}
.null:hover {
background-position: 0 100%;
background-size: 100% 1px;
}
}
@media(hover: none) {
.dk-jeihhc {}
.null:active {
background-position: 0 100%;
background-size: 100% 1px;
}
}
.dk-jeihhc {
position: relative;
display: inline-flex;
align-items: center;
pointer-events: auto;
opacity: 1;
text-decoration: none;
background-image: linear-gradient(currentColor, currentColor);
background-repeat: no-repeat;
transition: background-size .3s;
background-position: 100% 100%;
background-size: 0 1px;
}
@media(hover: hover) {
.dk-jeihhc {}
.null:hover {
background-position: 0 100%;
background-size: 100% 1px;
}
}
@media(hover: none) {
.dk-jeihhc {}
.null:active {
background-position: 0 100%;
background-size: 100% 1px;
}
}
I see a few weird things happening, but most importantly, the media queries are broken. &:hover
becomes .null:hover
Am I doing it wrong?
This is a feature(s) request.
@dark-engine/core
currently doesn't have error boundaries.
Error boundaries are similar to Suspense
: while Suspense
"catches" promises, error boundaries catch errors. For this reason, in the React ecosystem these 2 are used together.
An error boundary would simplify useQuery
usage with the suspense-only
strategy, given the following changes:
isFetching
error && (typeof data === 'undefined')
. This error can be caught by an error boundaryThis behavior guarantees data
is defined when the component renders. Error handling and fallback can be moved outside of the component definition.
This feature request should be marked with low priority since useQuery
{strategy: 'state-only'}
is also available and would remain unchanged.
I am trying to use data
.
~~It seems like useQuery
hangs until timeout if the server api object contains a fetch call. ~~
The API endpoint receives no requests, as if fetch was not called.
// On the server
const api = {
// retrieveAdmin: () => fetch(`${config.apiUrl}/euxenite/auth`) // this hangs the server
retrieveAdmin: () => fetch(`https://google.com`) // this works
// retrieveAdmin: () => new Promise((resolve) => { // this works fine
// setTimeout(() => {
// resolve(testObject)
// }, 1000)
// })
}
}
// In the component
const res = useQuery('adminData', api.retrieveAdmin)
I am on Bun, Bun does support fetch, and it shouldn't be the cause of the issue. Is the server implementation of data
supposed to work differently?
It looks like the problem is not fetch. The api url I provided was bad, but I did not expect useQuery
to hang forever, I expected a network error to be returned
I noticed that the server waits the 1s timeout I set before it returns the response to the browser (of course).
In testing, with the api on the same machine, there shouldn't be much wait time. But in production, what happens if a data source doesn't respond quickly enough?
Because useQuery uses the api object that has the same type on server and browser, is it impossible to useQuery on browser only for some api properties? Or maybe a way to use useQuery
on the browser only, despite a SSR setup?
I am confused by how route paths work.
I define routes without trailing slashes
{
path: '/contact',
pathMatch: 'full',
component: lazy(() => import('../pages/Contact')),
},
When I navigate to /contact
the path matches the route and it renders the Contact
component.
When I navigate to /contact/
is also matches.
On /contact
, useMatch().path
returns /contact/
.
<RouterLink to='/contact'>Contact</RouterLink>
bring me to /contact/
.
This made me think that routes should always have trailing slashes, but this was a mistake.
{
path: '/contact/',
pathMatch: 'full',
component: lazy(() => import('../pages/Contact')),
},
When I navigate to /contact
the path does not match.
Is there a way to:
/contact
/contact
from /contact/
/contact/
match the path /contact
tooTrailing slashes are unusual to see. Right now I can see https://github.com/atellmer/dark/issues/new
in this tab, not https://github.com/atellmer/dark/issues/new/
P.S. is this router based on another router project? I am curious
The comment breaks the both the &::selection
selector styles and the media queries.
This does not happen when comments do not contain functions.
const HeroHeading = styled.h2`
/* font-family: ${props => props.theme.displayFont}; */
line-height: 1;
font-size: 180%;
&::selection{
background: ${props => props.theme.selection};
}
${props => css`
@media (min-width: ${props.theme.sm}) {
margin: 0 0 0 auto;
font-size: 500%;
}
@media (min-width: ${props.theme.xl}) {
font-size: 700%;
}
@media (min-width: ${props.theme.xxxl}) {
font-size: 900%;
}
`}
`
const Message = component(({ className, defaultMessage, id, ...values }) => {
const { translator } = useTranslation()
const { getMessageById, currentLanguage, onError } = translator
const message = getMessageById(id, defaultMessage)
if (detectIsString(message)) {
try {
const parts = getTranslationParts(currentLanguage, message, values)
const result = []
for (let i = 0, len = parts.length; i < len; i++) {
const part = parts[i]
if (detectIsVirtualNode(part)) {
result.push(cloneVNode(part, { key: i })) // cloneVNode/cloneElement doesn't exist
} else {
result.push(<Fragment key={i}>{part}</Fragment>)
}
}
return <>{result}</>
} catch (error) {
onError(new TranslationError(id, currentLanguage))
}
}
return <>{String(message)}</>
})
export default Message
I am looking to clone an element in an iteration. I see here that keys can be added to elements in iterations.
<StyledHeader
isVisible={true}
isAtTop={true}
>
Results in
<header isVisible isAtTop class="dk-gbhdaf dk-hcdaig dk-bhjaad">
I'm debugging this component, with this example.
The CurrencyInput
component passes a string value
to the child <input />
. With onInput
events, the value
(result of getRenderValue
) changes to the expected value, but:
input
child renders true
instead of the passed value
prop.formatValue
function, are displayed by the input
child, despite not being the result of the getRenderValue
function (and therefore the value of the value
prop).In these cases, the input
child is not respecting the value
prop.
I think this is a bug, #82 solved some issues, this is new. I can't tell if this was also happening before.
Web router expects factory functions in the component
field, which means I cannot do
// ./routes.jsx
import AuthProvider from './components/AuthProvider'
const Dashboard = lazy(() => import('./pages/Dashboard'))
export const routes = [
{
path: '/',
component: Root,
children: [
{
path: '',
component: <AuthProvider><Dashboard /></AuthProvider>
},
{
path: 'login',
component: lazy(() => import('./pages/Login'))
},
{
path: 'not-found',
component: lazy(() => import('./pages/NotFound'))
},
{
path: '**',
redirectTo: 'not-found'
}
]
}
]
I also cannot do
// ./pages/Dashboard.jsx
export default AuthProvider(Dashboard)
How does one implement "protected routes" with web-router?
I am experiencing hydration errors seemingly caused by the useQuery hook.
I'm trying to reproduce it reliably but I am having trouble with that, as the hook works fine in isolation.
So far all I can tell is that adding one useQuery hook that works fine in isolation, to a page with more than one useQuery hook, seems to cause a hydration error.
I will try to investigate further.
A relatively smaller version of my app is here with comments and repro steps.
In this repository you can also observe the DisplayCatalogItems
component possesses the <Link />
isssue discussed in #77
I have discovered a workaround for these useQuery hydration errors, it involves wrapping the components using useQuery in more html elements.
I have noticed that the base64 encoded state the server produces contains duplicated content. Is this expected?
paltform-browser
's render
function rejects document
as parameter because document instanceof Element
evaluates to false
.
A few small changes should allow the render
function to correctly handle the entire document as root.
I have encountered a bug with dark-styled.
const GlobalStyle = createGlobalStyle`
@font-face {
font-family: 'SomeFontName';
font-weight: normal;
font-style: normal;
font-display: swap;
src: url('/_public/fonts/SomeFontNameRegular.woff2') format('woff2');
}
html,
body {
font-family: 'SomeFontName';
}`
const StyledHeader = styled.header`color: black;`
const Root = component(({ slot }) => {
return (
<>
<GlobalStyle />
<StyledHeader />
{slot}
</>
<style dark-styled="g">
@font-face {
font-family: 'SomeFontName';
font-weight: normal;
font-style: normal;
font-display: swap;
src: url('/_public/fonts/SomeFontNameRegular.woff2') format('woff2');
}
html, body {
font-family: 'SomeFontName';
}
</style>
,<style dark-styled="c">
.dk-baacag {
color: black;
}
</style>
As you can see there is an unwanted comma on this line ,<style dark-styled="c">
that is rendered in the document.
This comma shows above the content
@dark-engine/platform-server
contains the statement import { Readable } from 'node:stream'
.
Readable is global, it doesn't need to be explicitly imported.
Bun implements the Node Readable class. Commenting out the import statement allows @dark-engine/platform-server
to successfully run on Bun.
Will verify and update
Using Bun and SSR on Bun, as usual according to my starter template
import SomeFontNameRegular from '../assets/fonts/SomeFontNameRegular.woff2'
const GlobalStyle = createGlobalStyle`
@font-face {
font-family: 'SomeFontName';
font-weight: normal;
font-style: normal;
font-display: swap;
src: url(${SomeFontNameRegular}) format('woff2');
}
html,
body {
font-family: 'SomeFontName';
}`
const Root = component(({ slot }) => {
return (
<>
<GlobalStyle />
{slot}
</>
This results in a not found error: the server responds with this
<style dark-styled="g">
@font-face {
font-family: 'SomeFontName';
font-weight: normal;
font-style: normal;
font-display: swap;
src: url(/home/coachonko/Documents/projects/frontend/dark-website/src/assets/fonts/SomeFontNameRegular.woff2) format('woff2');
}
html, body {
font-family: 'SomeFontName';
}
</style>
As you can see the url is resolved as an absolute path. Bun imports the file as an asset and the file name is SomeFontNameRegular-hash.woff2 and it is placed in the build directory.
The correct file is imported anyway because the correct url is resolved on the browser.
@font-face{font-family:'SomeFontName';font-weight:normal;font-style:normal;font-display:swap;src:url(/_dark/SomeFontNameRegular-1b44130d820257be.woff2) format('woff2');}html,
body{font-family:'SomeFontName';}
Is this expected?
As a workaround, I can put the font files in the public directory of my project and use absolute URLs instead of importing the files as assets with bun.
Note the public directory in the starter template works like a nextjs / vite public directory.
I have tried to setup SSR with renderToString and styled dark components and I found it confusing.
The documentation says a provider can be added to your component tree, which accepts styles through a context API
but it is not shown how to do that, instead String.replace
method is used.
The String.replace
method seems to work, but it is not clear if the provider is implemented or not yet
I have encountered a behavior to investigate further:
const DynamicPageMeta = component(({ currentPath, slug, language }) => {
const { data } = useCatalogQuery(catalogQueries.product, { slug })
if (!data) {
return null
}
const product = data[0]
if (detectIsUndefined(product)) {
return null
}
console.log('data exists') // this appears in the console
return (
<>
<DynamicPageOpenGraphMeta currentPath={currentPath} slug={slug} language={language} />
<DynamicPageTwitterMeta slug={slug} language={language} />
</>
)
})
This is the component in which the issue was identified.
The DynamicPageOpenGraphMeta
is rendered correctly, the DynamicPageTwitterMeta
is not rendered.
const DynamicPageTwitterMeta = component(({ slug, language }) => {
console.log('DynamicPageTwitterMeta rendered') // this does not appear in the console
Adding a Fragment between the 2 components solves the issue, and DynamicPageTwitterMeta
is rendered.
return (
<>
<DynamicPageOpenGraphMeta currentPath={currentPath} slug={slug} language={language} />
<></> {/* This fragment seems to solve the issue */}
<DynamicPageTwitterMeta slug={slug} language={language} />
</>
)
Adding a null
between the 2 components also seems to solve the issue
return (
<>
<DynamicPageOpenGraphMeta currentPath={currentPath} slug={slug} language={language} />
{null}
<DynamicPageTwitterMeta slug={slug} language={language} />
</>
)
This tree is rendered with renderToString
.
The resulting function after bundling is as follows:
var DynamicPageMeta = component(({ currentPath, slug, language }) => {
const { data: data5 } = useCatalogQuery(catalogQueries.product, { slug });
if (!data5) {
return null;
}
const product = data5[0];
if (detectIsUndefined(product)) {
return null;
}
return jsx(Fragment, {
children: [
jsx(DynamicPageOpenGraphMeta, {
currentPath,
slug,
language
}, undefined, false, undefined, this),
jsx(DynamicPageTwitterMeta, {
slug,
language
}, undefined, false, undefined, this)
]
}, undefined, true, undefined, this);
});
Adding the fragment results in this:
return jsx(Fragment, {
children: [
jsx(DynamicPageOpenGraphMeta, {
currentPath,
slug,
language
}, undefined, false, undefined, this),
jsx(Fragment, {}, undefined, false, undefined, this),
jsx(DynamicPageTwitterMeta, {
slug,
language
}, undefined, false, undefined, this)
]
}, undefined, true, undefined, this);
Adding the null results in this:
return jsx(Fragment, {
children: [
jsx(DynamicPageOpenGraphMeta, {
currentPath,
slug,
language
}, undefined, false, undefined, this),
null,
jsx(DynamicPageTwitterMeta, {
slug,
language
}, undefined, false, undefined, this)
]
}, undefined, true, undefined, this);
I can provide a replication in private shortly, a public replication will require more time.
I apologize, this is not repro code, this is the exact code where I have experienced this issue for the third time.
When a Link component wraps an element, a full page refresh is triggered on click.
I do not exactly know in which situation this happens exactly. Some elements are ok some aren't.
const PaintingsLinksSection = styled.section`
${props => fragmentContainerPadding(props)}
`
const PaintingsLinksWrapper = styled.div`
${props => css`
@media (min-width: ${props.theme.sm}) {
display: inline-block;
width: 47.5%;
}
`}
`
const PaintinksLinksSeparator = styled.div`
${props => css`
@media (min-width: ${props.theme.sm}) {
display: inline-block;
width: 2.5%;
}
`}
`
const PaintingsLinksImageContainer = styled.div`
height: 80svh;
`
const PaintingsLinksImage = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
`
const PaintingsLinks = component(({ homePath }) => {
return (
<PaintingsLinksSection>
<Link to={`${homePath}my-art/available`}>
<PaintingsLinksWrapper>
<PaintingsLinksImageContainer>
<PaintingsLinksImage src='_public/hero.jpg' alt='TODO' />
</PaintingsLinksImageContainer>
</PaintingsLinksWrapper>
</Link>
<PaintinksLinksSeparator />
<Link to={`${homePath}my-art/available`}>
<PaintingsLinksWrapper>
<PaintingsLinksImageContainer>
<PaintingsLinksImage src='_public/hero.jpg' alt='TODO' />
</PaintingsLinksImageContainer>
</PaintingsLinksWrapper>
</Link>
</PaintingsLinksSection>
)
})
The following works as expected and I use this as workaround.
const PaintingsLinksSection = styled.section`
${props => fragmentContainerPadding(props)}
`
const PaintingsLinksWrapper = styled.div`
position: relative;
${props => css`
@media (min-width: ${props.theme.sm}) {
display: inline-block;
width: 47.5%;
}
`}
`
const PaintinksLinksSeparator = styled.div`
${props => css`
@media (min-width: ${props.theme.sm}) {
display: inline-block;
width: 2.5%;
}
`}
`
const PaintingsLinksImageContainer = styled.div`
height: 80svh;
`
const PaintingsLinksImage = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
`
const PaintingsLinksLink = styled(Link)`
position: absolute;
inset: 0;
`
const PaintingsLinks = component(({ homePath }) => {
return (
<PaintingsLinksSection>
<PaintingsLinksWrapper>
<PaintingsLinksImageContainer>
<PaintingsLinksImage src='_public/hero.jpg' alt='TODO' />
</PaintingsLinksImageContainer>
<PaintingsLinksLink to={`${homePath}my-art/available`} />
</PaintingsLinksWrapper>
<PaintinksLinksSeparator />
<PaintingsLinksWrapper>
<PaintingsLinksImageContainer>
<PaintingsLinksImage src='_public/hero.jpg' alt='TODO' />
</PaintingsLinksImageContainer>
<PaintingsLinksLink to={`${homePath}my-art/available`} />
</PaintingsLinksWrapper>
</PaintingsLinksSection>
)
})
I have a component with this sort of query
// suppose the parent component has a button that toggles an `availability: 'true'` property in the `params` object
const ShopItems = component(({ params }) => {
console.log(params) // diagnose params changes
const api = useApi()
const { data, isFetching, error } = useQuery(
'tools',
(params) => api.catalogRetrieve({ category: 'tools', ...params }),
{ variables: params, extractId: () => hashKey(params) },
)
According to the documentation here, this setup allows the query to refetch whenever variables change.
With this code, a refetch happens when the params
object changes from
Case A: returns an array of 10 items
{
"status": "public"
}
to
Case B: returns an array of 4 items
{
"status": "public",
"availability": "true"
}
Then, if the property availability
is removed from the params
object again, a refetch does not happen and data
does not change. data
returned is still an array of 4 items instead of 10. No errors are thrown either.
I am confused because I expected it to maybe not refetch, because the key already exists in cache, but I did not expect the data object to not change either.
What am I doing wrong?
I have questions about useTransition
.
I can't figure out how to do page transitions with it, what is the purpose of the second parameter KeyExtractor?
// Desperate attempt at page transitions
const PageTransition = component(({ slot }) => { // I want both layout and child route to yeet out of the way
const { pathname } = useLocation() // when pathname changes, slot changes
const [transition] = useTransition([pathname], x => x, () => ({ // first param must be array
// some random test properties
from: { opacity: 0, transform: 'translate3d(100vw, 0, 0)' },
enter: { opacity: 1, transform: 'translate3d(0, 0, 0)' },
leave: { opacity: 0, transform: 'translate3d(-20vw, 0, 0)' },
}));
return transition(({ spring, item }) => { // item is just pathname
return (
<Animated spring={spring}>
{slot}
</Animated>
)
})
})
// all routes in my app are children of Root
const Root = component(({ slot }) => {
return (
<>
<GlobalStyle />
<PageTransition>
<LayoutComponents>
{slot}
</LayoutComponents>
</PageTransition>
</>
)
})
// error: TypeError: x.toFixed is not a function. (In 'x.toFixed(precision)', 'x.toFixed' is undefined)
What I am trying to achieve goes beyond this, but I am stuck here at the most basic attempt
I need a function that would return me if a route is matched for a given path.
Something like matchRoute(routesArray, path)
which return null or an array of matched routes.
This is because I need to be able to "filter" valid requests before hanging them to my Dark server script, otherwise Dark will render the application and return HTML when a non-existing file is requested.
With a matchRoute
function that returns null
or an array where matchRouteArr[0].path === '**'
, I can immediately send an error 404, making my Dark server more efficient
import { join } from 'bun:path'
// tryFiles returns a static file from the build directory, if found. otherwise it passes the request
// to the specified handler.
export function tryFiles (elysiaContext, publicDir, handler) {
const absolutePath = join(process.cwd(), publicDir, elysiaContext.path)
// prevent relative path abuse
const allowedBasePath = join(process.cwd(), publicDir, '/')
if (!absolutePath.startsWith(allowedBasePath)) {
return elysiaContext.error(403) // 'Forbidden'
}
if (absolutePath === allowedBasePath) {
return handler(elysiaContext)
}
const file = Bun.file(absolutePath)
// TODO if file is missing and not an application route, the handler (Dark) will return HTML. This is a problem.
// Check application routes: if match give request to Dark, otherwise return elysiaContext.error(404) immediately
if (file.size === 0) {
return handler(elysiaContext)
}
return file
}
Update: I think there is a huge flaw in what I was attempting to do, and I will change my logic for sure. However, this function may still be useful to have.
const LinksRow = styled.div`
display: flex;
justify-content: space-between;
gap: 2.5vw;
& ul {
list-style-type: none;
padding: 0;
margin: 0;
width: 100%;
}
& ul li {
list-style: none;
border-bottom: ${props => props.theme.borderStyle};
}
& ul li a {
display: flex;
justify-content: space-between;
align-items: center;
text-decoration: none;
color: ${props => props.theme.black};
padding: .5vw 0;
transition: color .2s, background-color .2s, padding .3s;
}
& ul li a:hover {
color: ${props => props.theme.white};
background-color: ${props => props.theme.black};
padding: .5vw;
}
@media (prefers-reduced-motion: reduce) {
& ul li a {
transition: none;
}
}
`
the media query style is outputted before the & ul li a
style.
@media (prefers-reduced-motion: reduce) {
.dk-cadhch {}
.dk-cadhch ul li a {
transition: none;
}
}
.dk-bfhafa {}
.dk-bfhafa ul li {
list-style: none;
border-bottom: solid 1px #1e1f1f;
}
.dk-bdfidj {}
.dk-bdfidj ul li a {
display: flex;
justify-content: space-between;
align-items: center;
text-decoration: none;
color: #1e1f1f;
padding: .5vw 0;
transition: color .2s, background-color .2s, padding .3s;
}
Because they have the same specificity, the browser ignores the media query styles. I believe the media query should be put after the styles defined before it.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.