Skip to content

Revamp events #136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ethul opened this issue Mar 4, 2018 · 3 comments
Closed

Revamp events #136

ethul opened this issue Mar 4, 2018 · 3 comments

Comments

@ethul
Copy link
Contributor

ethul commented Mar 4, 2018

Before the next major release, I was thinking of looking into options to update the way events are represented to tackle some issues brought up regarding events: #135, #85.

One option suggested in #135 (comment) could be a good way to go for this.

Thoughts and ideas on this are welcome!

/cc @natefaubion

@natefaubion
Copy link
Contributor

One thing to consider is that events in React are pooled by default, and it's not safe to hold on to references of them without taking precautions (https://reactjs.org/docs/events.html#event-pooling).

@ethul
Copy link
Contributor Author

ethul commented Mar 4, 2018

Good to know. Thanks for the link.

@ethul
Copy link
Contributor Author

ethul commented Apr 4, 2018

Apologies on the delay here.

I was thinking of a couple of options in terms of implementation.

Option 1 - Typeclasses

The main idea here is to define foreign data for each type of event, along with a typeclass. If an even type has an instance of the typeclass then the associated functions could be called for the given event type. For example, all of the events types would have an instance of IsSyntheticEvent. See below for a snippet of what this could look like.

foreign import data SyntheticEvent :: Type

class IsSyntheticEvent a where
  toSyntheticEvent :: a -> SyntheticEvent

instance isSyntheticEventSyntheticEvent :: IsSyntheticEvent SyntheticEvent where
  toSyntheticEvent = id

instance isSyntheticEventSyntheticClipboardEvent :: IsSyntheticEvent SyntheticClipboardEvent where
  toSyntheticEvent = unsafeCoerce

...etc

bubbles :: forall a. IsSyntheticEvent a => a -> Boolean
bubbles = (#) _.bubbles <<< unsafeCoerce <<< toSyntheticEvent

cancelable :: forall a. IsSyntheticEvent a => a -> Boolean
cancelable = (#) _.cancelable <<< unsafeCoerce <<< toSyntheticEvent

currentTarget :: forall a. IsSyntheticEvent a => a -> DOMEventTarget
currentTarget = (#) _.currentTarget <<< unsafeCoerce <<< toSyntheticEvent

nativeEvent :: forall a. IsSyntheticEvent a => a -> DOMEvent
nativeEvent = (#) _.nativeEvent <<< unsafeCoerce <<< toSyntheticEvent

preventDefault :: forall eff a. IsSyntheticEvent a => a -> Eff eff Unit
preventDefault = (#) _.preventDefault <<< unsafeCoerce <<< toSyntheticEvent

stopPropagation :: forall eff a. IsSyntheticEvent a => a -> Eff eff Unit
stopPropagation = (#) _.stopPropagation <<< unsafeCoerce <<< toSyntheticEvent

...etc

foreign import data SyntheticClipboardEvent :: Type

class IsSyntheticClipboardEvent a where
  toSyntheticClipboardEvent :: a -> SyntheticClipboardEvent

instance isSyntheticClipboardEventSyntheticClipboardEvent :: IsSyntheticClipboardEvent SyntheticClipboardEvent where
  toSyntheticClipboardEvent = id

clipboardData :: forall a. IsSyntheticClipboardEvent a => a -> DOMDataTransfer
clipboardData = (#) _.clipboardData <<< unsafeCoerce <<< toSyntheticClipboardEvent

...etc

Option 2 - Records

Another option is to continue with how the React module is currently working, using records to define the properties of the events. However, use extensible records if events share common properties. See below for wha this could look like.

type SyntheticEvent eff r
  = { bubbles :: Boolean
    , cancelable :: Boolean
    , currentTarget :: DOMEventTarget
    , defaultPrevented :: Boolean
    , eventPhase :: Number
    , isTrusted :: Boolean
    , nativeEvent :: DOMEvent
    , preventDefault :: Eff eff Unit
    , isDefaultPrevented :: Eff eff Boolean
    , stopPropagation :: Eff eff Unit
    , isPropagationStopped :: Eff eff Boolean
    , target :: DOMEventTarget
    , timeStamp :: Number
    , type :: String
    | r
    }

type SyntheticKeyboardEvent eff
  = SyntheticEvent eff
      ( altKey :: Boolean
      , charCode :: Int
      , ctrlKey :: Boolean
      , getModifierState :: String -> Boolean
      , key ::  Boolean
      )

...etc

I am curious to hear what people think of the two options and if one option is preferred over the other. Or if someone has another option not listed above, I am definitely open to hear about it.

@ethul ethul mentioned this issue Apr 10, 2018
ethul added a commit that referenced this issue Apr 14, 2018
Resolves #85
Resolves #135
Resolves #136
ethul added a commit that referenced this issue Apr 14, 2018
Resolves #85
Resolves #135
Resolves #136
ethul added a commit that referenced this issue Apr 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants