Code Monkey home page Code Monkey logo

focal's People

Contributors

a-gambit avatar andrei-zhidkov avatar blacktaxi avatar compuives avatar dependabot[bot] avatar drakosvlad avatar gabebw avatar github-actions[bot] avatar igorbek avatar oleksiilevzhynskyi avatar opudalo avatar valentyng avatar wenqer avatar zlldnv 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 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

focal's Issues

How to integrate third-party React components?

This is a question, I am sure I saw some info on how to do this (maybe Reactive2017 conf?).

How can I use third-party React components with Focal? For example https://github.com/MadRabbit/a-plus-forms.
This works, but is there another way?

<F.div>
      You have clicked this button {count} time(s).
      <Form onSubmit={...}>
        <TextInput name="username" label={<F.span>{count}</F.span>} />
      </Form>
    </F.div>

This fails (as excpected I guess):

<F.div>
      You have clicked this button {count} time(s).
      <Form onSubmit={...}>
        <TextInput name="username" label={count} />
      </Form>
    </F.div>

This shows the first count value, but does not update after first render.

<F.div>
      You have clicked this button {count} time(s).
      <Form onSubmit={...}>
        <TextInput name="username" label={count.get()} />
      </Form>
    </F.div>

Any CRUD example?

Do you have any examples for syncing local UI state and server state?
I see some examples for fetching data from server (github search for example)
But there is no example for crud operations.

I can see some possibilities here:

  1. Initiate server calls to modify data directly from react component callbacks
  2. Listen to observable state and save data from it to server when state is modified. (for example, I can introduce some markers for data changed. So I can update it on the server)

What do you think about these possiblities? What's better from your point of view? Or maybe you have some other experience?
It would be great if you add some examples for novices

React hooks

Would it make sense to have a react hook, for example useAtom that would subscribe to the atom, and return the latest value?

For example, you'd use it something like this:

import * as React from 'react'
import { Atom } from '@grammarly/focal'

const store = {
  count: Atom.create(0)
}

const Counter = () => {
  const count = useAtom(store.count)

  return (
    <div>Count: {count}</div>
  )
}

Array lens created through Prism sets array element to `undefined`

When a Lens created through a Lens.index(...) prism with default value V it sets associated array element into undefined in being set with that value V.
E.g.:

const states = Atom.create([])  // Array of strings
states.set(['hidden', 'hidden'])
const lens = states.lens(Lens.index(0).compose(Lens.withDefault('hidden')))
// ...
lens.set('visible') // works just fine
lens.set('hidden') // sets states[0] to `undefined`

Two points here:

  • I assume expected behavior is to return default value if array[i] is undefined by set whatever is passed to lens.set()
  • Returning an optional from states.lens(Lens.index(0)) is not very convenient IMO

Can't build a project

screen shot 2018-10-07 at 12 16 23

Package.json:
"dependencies": {
    "@grammarly/focal": "^0.7.0",
    "preact": "^8.3.1",
    "ramda": "^0.25.0",
    "recompose": "^0.30.0",
    "rxjs": "^6.3.2",
    "undux": "^3.2.1"
  },
  "devDependencies": {
    "@babel/plugin-transform-modules-commonjs": "^7.1.0",
    "@types/chrome": "~0.0.72",
    "@types/jest": "^23.3.2",
    "@types/node": "^10.11.3",
    "@types/ramda": "^0.25.38",
    "@types/rx": "^4.1.1",
    "clean-webpack-plugin": "^0.1.19",
    "copy-webpack-plugin": "^4.5.2",
    "css-loader": "^1.0.0",
    "jest": "^23.6.0",
    "preact-compat": "^3.18.4",
    "style-loader": "^0.23.0",
    "ts-jest": "23.1.4",
    "ts-loader": "~5.0.0",
    "typescript": "^3.1.1",
    "webpack": "~4.17.2",
    "webpack-archive-plugin": "^3.0.0",
    "webpack-cli": "~3.1.0",
    "webpack-merge": "~4.1.4",
    "webpack-zip-files-plugin": "^1.0.0"
  }

Set state in state.subscribe()

Hi, I find focal very interesting, since it tries to use both imperative and functional approaches.

I played around and wanted to implement a pattern, where a click merely proposes new state value. Then a central function decides if the state has to be modified. It seems to work surprisingly, if I directly mutate the state in a state-subscription.

Do you think this is very wrong and that it is a "loophole" in the API that might not work correctly? I just tried the example from your Readme, where I added a Toggle component.

(Btw. I do not use Typescript)

import * as React from "react";
import { Atom, F } from "@grammarly/focal";

export default ({ shim }) => {

  const Counter = ({ count, onClick }) => (
    <F.div>
      You have clicked this button {count} time(s).
      <button onClick={onClick}>Click again?</button>
    </F.div>
  );

  const Toggle = ({ value, onClick }) => (
    <F.div>
      clickValue: {value}&nbsp;
      <button onClick={onClick}>toggle</button>
    </F.div>
  );

  const App = ({ state }) => (
    <div>
      Hello, world!
      <Counter
        count={state.view(x => x.count)}
        onClick={() => state.lens(x => x.count).modify(x => x + 1)}
      />
      <Toggle
        value={state.view(x => (x.toggle.value ? "Foo" : "Bar"))}
        onClick={() =>
          state.lens(x => x.proposal).modify(x => ({ toggle: !x.toggle }))}
      />
    </div>
  );

  const state = Atom.create({
    count: 0,
    toggle: { value: true },
    proposal: {}
  });

  state.subscribe(x => {
    console.log(`New app state: ${JSON.stringify(x)}`);
  });

  state
    .skip(1)
    .distinct(x => x.proposal)
    .do(x => {
      console.log("Proposal changed", x.proposal);
      if (x.proposal.toggle !== undefined) {
        x.toggle.value = !x.toggle.value; // This seems to actually work.
      }
    })
    .subscribe();

  return <App state={state} />;
};

Publish Atom/Lens-only version

I love the concept of Atom and wish I could use it on non-React projects. Unfortunately, using this library forces me to pull in all of React to compile.

[Questions] React Ecosystem Support: CRA & React Native?

Hi!

I'm seriously considering using Focal, but couldn't find docs to answer two of our higher-priorities:

  1. I noticed the <F.div> component looks like a pretty serious investment of time for your team to have produced. I couldn't find an analog for React native in your repo anywhere and assume you aren't currently using Focal with React Native. Am I mistaken? If not, have you any plans to create an observer <F.view> or the like?
  2. Would I be able to customize a create-react-app to leverage Focal or is it currently just "clone" and figure it out? Just curious.

Thank you for the documentation! It's very concise! I'm very excited to see movement in this area!

Problem with .view and unsubscribe

After unsubscribing from ReadonlyAtom (created by .view) it still calling function inside, fails and unsubscribing.

In other words - if we unsubscribe from ReadonlyAtom - it don't unsubscribe from inner subscription.

const state = Atom.create([{ id: 1 }])

  const view = state.view(state => state[0].id) //if we replace view with map - it works

  const sub = view.subscribe(s => {
    console.log(s)
  })

  state.modify(s => {
    sub.unsubscribe()
    return []
  })

This causing a problem with reactiveList.

{reactiveList(
        state.map(s => s.map((_, ind) => ind)),
        ind => {
          return <El el={state.view(s => s[ind].id)} /> //view is already unsubscribed from this observable, but `.view` is still calling. 
        }
  )}

I guess problem is here https://github.com/grammarly/focal/blob/master/src/atom/base.ts#L378

Typescript error with strictNullChecks

Trying to use focal with Typescript 3.4.3, I get

node_modules/@grammarly/focal/dist/src/react/react.d.ts:103:5 - error TS2411: Property 'mount' of type 'undefined' is not assignable to string index type '((e: SyntheticEvent<any, Event>) => void) | ((domElement: Element | null) => void)'.

103     mount?: undefined;
        ~~~~~

and a similar error for ref. I'm able to get rid of the error if I turn off strictNullChecks in my tsconfig.json, but I don't want to do that :(.

Also I'm confused because the tsconfig.jsons for focal has strictNullChecks turned on; in fact, I get the same error when I try to build the examples following the instructions.

Another way I found to fix it (without turning off strictNullChecks) is to remove the mount?: undefined and ref?: undefined lines from the type of bindElementProps in react.d.ts. I don't understand where those lines come from, given the code of bindElementProps; seems like a possible Typescript bug?

Fix `instanceof Observable` check

The current instanceof Observable check that is used in the implementation of lifted component relies on the class instance check, which in turn requires that the instance be checked against the same constructor it was created with.

However it is possible that user-created Observables come from a different version or just a different instance of the rxjs package. In that case the instanceof Observable check will always fail.

It seems that the issue of several rxjs packages in a bundle should not be affecting Focal, or if it does there should be a quick way to diagnose the issue.

One solution that I see is the adoption of symbol-observable check like it's done in Redux, etc.

Uncaught TypeError: f.a.key is not a function

Hello!

I use Create React App. On dev environment everything goes well, but the production build goes broken.

base.ts:292 Uncaught TypeError: f.a.key is not a function
    at t.lens (base.ts:292)
    at Module.71 (state-app.ts:26)
    at l ((index):2)
    at Object.66 (main.c2bc3c36.chunk.js:1)
    at l ((index):2)
    at a ((index):2)
    at Array.e [as push] ((index):2)
    at main.c2bc3c36.chunk.js:1

Here is base.ts source map:

    AbstractAtom.prototype.lens = function (arg1) {
        // tslint:disable no-use-before-declare
        var args = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            args[_i - 1] = arguments[_i];
        }
        // lens(prop expr) case
        return typeof arg1 === 'function'
            ? new LensedAtom(this, Lens.prop(arg1), structEq)
            // lens('key') case
            : typeof arg1 === 'string'
                ? new LensedAtom(this, Lens.compose.apply(Lens, [Lens.key(arg1)].concat(args.map(function (k) { return Lens.key(k); }))), structEq)
                // lens(lens) case
                : new LensedAtom(this, arg1, structEq);
        // tslint:enable no-use-before-declare
    };
    return AbstractAtom;
}(AbstractReadOnlyAtom));

Problem happens in this string:
? new LensedAtom(this, Lens.compose.apply(Lens, [Lens.key(arg1)].concat(args.map(function (k) { return Lens.key(k); }))), structEq)

More precisely this sub-string: Lens.compose.apply(Lens, [Lens.key(arg1)]

Where is Lens.key is not a function.

I've tried to turn off mangle in TerserPlugin which minify the code and it had no results.

Now I'm thinking about the sequence of function calls, mb it works differently in dev and prod env.

I hope you have some ideas what should I try next to make it works.
You can explore the source-code here: https://github.com/sukazavr/dego.app
And of course you can build it on your local machine and test it out by yourself.
Thank you!

No "empty observable" warning when using a single empty Observable prop

Currently, there is an inconsistency between the single vs. multiple Observable props warning policies.
Namely, Focal will warn about empty observable in props only when there's more than one observable passed. The example is available here (thanks @oleksiilevzhynskyi).
It looks like it's because RenderMany class reports the warning right after walking the observables, while RenderOne will warn the user only after Observable's completion, which may not happen at all.

Is there any specific reason for waiting for the completion in case of a single prop? It feels a bit misleading that the same issue is treated differently.

Classes in Atoms lose their functions after modification

Due to the way setKey is written, the original prototype is forgotten. This means all of the functions disappear as well.

export function setKey<T, K extends keyof T>(k: K, v: T[K], o: T): T {
if (k in o && structEq(v, o[k])) {
return o
} else {
// this is the fastest way to do it, see
// https://jsperf.com/focal-setkey-for-loop-vs-object-assign
const r: { [k in keyof T]: T[k] } = {} as any
for (const p in o) r[p] = o[p]
r[k] = v
return r
}
}

Persistence

I was just curious how you guys implement persisting data to a backend. Being able to update a global data store locally is great, but how do you persist these changes to storage? Do you track changes and send the appropriate requests? Do you use some kind of operational transformation protocol?

Thanks!

Replace regex in Lens.prop with Proxy

Just stopping through reading your tutorial.

Before

focal/src/lens/json.ts

Lines 68 to 72 in 271e37d

export function extractPropertyPath<TObject, TProperty>(
target: PropExpr<TObject, TProperty>
): string[] {
return parsePropertyPath(target.toString())
}

After

type PropPath = (string | number | symbol)[]

function extractPropertyPath<Arg, Ret>(getter: PropExpr<Arg, Ret>): PropPath {
  const errorMessage = `Expected a property expression, got "${getter}"...`
  const props: PropPath = []
  getter(new Proxy(Object.create(null), {
    get(_, prop, proxy) {
      if (prop === Symbol.toPrimitive) {
        throw TypeError(errorMessage)
      }
      props.push(prop)
      return proxy
    },
  }) as Arg)
  return props
}

Demo

https://codepen.io/anon/pen/ejeWoL?editors=0011#0

Property 'lens' does not exist on type 'ReadOnlyAtom<State>'

I found this codesandbox that was shared by a Grammarly in an engineering post

In line 89 and 90, there is a Typescript compilation error

  const alerts = props.state.lens("alerts");
  const highlights = props.state.lens("highlights");

Property 'lens' does not exist on type 'ReadOnlyAtom<State>'

The code still works but I was intrigued by that knowing that method lens doesn't seem to appear in ReadOnlyAtom as reference here

Can someone explain what I could be missing here?

Should the object be Atom instead of ReadOnlyAtom?

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.