GithubHelp home page GithubHelp logo

atellmer / dark Goto Github PK

View Code? Open in Web Editor NEW
41.0 41.0 1.0 50.41 MB

The lightweight and powerful UI rendering engine without dependencies and written in TypeScript💫 (Browser, Node.js, Android, iOS, Windows, Linux, macOS)

License: MIT License

TypeScript 98.27% JavaScript 1.64% HTML 0.04% CSS 0.05%
angular components concurrent fiber framework frontend hooks jsx nativescript no-build-required nodegui performance react renderer server-side-rendering spring-animation typescript ui virtual-dom web

dark's Introduction

🐍 Don't tread on me

dark's People

Contributors

atellmer avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

coachonko

dark's Issues

No render, no error problem

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?

input value not being respected

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.

Delay useSpring animation

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

css fragment in GlobalStyle

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.)

Redirect/navigate on wildcard, how?

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?

Usage of <!--dark:matter-->

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

[data] Make dehydration of DataClient manual

I am using a Page component that has an App child component.
On the server:

  1. a DataClient is created and given to the App component
  2. The App component is rendered
  3. The DataClient 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.
  4. The Page component is rendered and used as response.

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.

styled does not minimize some rules

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 bootstrapScripts doesn't allow router's `lazy` to work

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

Debugging $$scope().getCursorFiber errors

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 error: Error: [@dark-engine/core]: The function was not installed by renderer! I was wrong
14:52: It was caused by useScrollbarWidth, now investigating why

Media queries and styled

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?

Error boundaries and useQuery

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:

  • Suspend when isFetching
  • Throw error when error && (typeof data === 'undefined'). This error can be caught by an error boundary

This 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.

[data] useQuery hangs forever instead of returning network error on bad URL

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?

web-router trailing slashes

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:

  • Make RouterLink navigate to /contact
  • Always remove trailing slashes
    • always redirect to /contact from /contact/
    • make routes defined as /contact/ match the path /contact too

Trailing 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

[styled] comment breaks styles

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%;
    }
  `}
`

Does a `CloneElement` function exist?

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.

input `value` prop not being enforced

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:

  • The input child renders true instead of the passed value prop.
  • Values such as letters that are cleaned by the 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] protected routes, how to implement them?

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?

[data] hydration errors

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?

Unwanted commas generated by dark-styled

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

`platform-server` Bun compatibility

@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

Importing fonts with styled: file urls on server

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.

Components not being rendered

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.

[web-router] weird behavior with children of Link

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>
  )
})

Question about data useQuery variables

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?

animations: useTransition usage

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

Utility function to detect whether a path matches a web-router route

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.

styled bad order

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.