{"id":13442712,"url":"https://github.com/helmutkian/cl-react","last_synced_at":"2026-01-19T14:03:26.362Z","repository":{"id":33388076,"uuid":"37033081","full_name":"helmutkian/cl-react","owner":"helmutkian","description":"Common Lisp (Parenscript) utilities for building web apps in ReactJs","archived":false,"fork":false,"pushed_at":"2020-11-21T18:51:05.000Z","size":85,"stargazers_count":69,"open_issues_count":4,"forks_count":2,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-20T15:40:15.764Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/helmutkian.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-07T21:31:30.000Z","updated_at":"2024-12-17T15:10:13.000Z","dependencies_parsed_at":"2022-08-07T21:01:28.964Z","dependency_job_id":null,"html_url":"https://github.com/helmutkian/cl-react","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/helmutkian/cl-react","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/helmutkian%2Fcl-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/helmutkian%2Fcl-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/helmutkian%2Fcl-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/helmutkian%2Fcl-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/helmutkian","download_url":"https://codeload.github.com/helmutkian/cl-react/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/helmutkian%2Fcl-react/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28571556,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T12:50:50.164Z","status":"ssl_error","status_checked_at":"2026-01-19T12:50:42.704Z","response_time":67,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T03:01:49.549Z","updated_at":"2026-01-19T14:03:26.344Z","avatar_url":"https://github.com/helmutkian.png","language":"Common Lisp","readme":"# cl-react\nCommon Lisp (Parenscript) utilities for building web apps in ReactJs\n \n### Installation\n\n* Clone the repo ``git clone https://github.com/helmutkian/cl-react.git``\n* Fire up your Common Lisp environment\n* Load the ASDF system definition ``(load \"\u003cpath to cl-react.asd\"\u003e)``\n* Load the system ``(ql:quickload 'cl-react)``\n* Build the JavaScript library ``(cl-react:build)``\n\n### PSX\n\nPSX is a Parenscript equivilent to JSX, ReactJs's extended JavaScript syntax. It uses the familiar CL-WHO syntax for markup generation.\n\n````common-lisp\n\n\n(ps:ps \n  (cl-react:psx \n    (:a :href (cl-react:with-ps (ps:@ this props site-url))\n      (:span :class \"text-green\" (cl-react:with-ps (ps:@ this props site-name))))))\n````\n\n=\u003e\n\n````javascript\n  React.DOM.a({ href: this.props.siteUrl }, [\n    React.DOM.span({ className: 'text-green' }, this.props.siteName)\n  ]);\n````\n\n### Convenience Functions / Macros\n\nCL-React contains some convenience aliases for commonly used React functions:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003cth\u003eLisp function\u003c/th\u003e\u003cth\u003eReact original\u003c/th\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003ecreate-class\u003c/td\u003e\u003ctd\u003eReact.createClass\u003c/td\u003e\u003c/tr\u003e \n\u003ctr\u003e\u003ctd\u003ecreate-element\u003c/td\u003e\u003ctd\u003eReact.createElement\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003ecreate-factory\u003c/td\u003e\u003ctd\u003eReact.createFactory\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eunmount-component-at-node\u003c/td\u003e\u003ctd\u003eReact.unmountComponentAtNode\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eis-valid-element\u003c/td\u003e\u003ctd\u003eReact.isValidElement\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003efind-dom-node\u003c/td\u003e\u003ctd\u003eReact.findDOMNode\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003erender\u003c/td\u003e\u003ctd\u003eReactDOM.render\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003erender-to-string\u003c/td\u003e\u003ctd\u003eReact.renderToString\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003erender-to-static-markup\u003c/td\u003e\u003ctd\u003eReact.renderToStaticMarkup\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003echildren-map\u003c/td\u003e\u003ctd\u003eReact.Children.map\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003echildren-count\u003c/td\u003e\u003ctd\u003eReact.Children.count\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003echildren-only\u003c/td\u003e\u003ctd\u003eReact.Children.only\u003c/td\u003e\u003c/tr\u003e\n\n\u003ctr\u003e\u003ctd\u003e(prop \u003ci\u003eitem\u003c/i\u003e)\u003c/td\u003e\u003ctd\u003ethis.props.\u003ci\u003eitem\u003c/i\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e(state \u003ci\u003eitem\u003c/i\u003e)\u003c/td\u003e\u003ctd\u003ethis.state.\u003ci\u003eitem\u003c/i\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e(set-state \u003ci\u003eitem\u003c/i\u003e \u003ci\u003evalue\u003c/i\u003e)\u003c/td\u003e\u003ctd\u003ethis.setState(\u003ci\u003eitem, value\u003c/i\u003e)\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n####Def-component\nThe def-component macro is a wrapper around create-class.\n\nA typical create-class might look like this:\n\n````common-lisp\n(var sample-component\n     (create-class\n       (create\n         get-initial-state\n         (lambda () ...)\n         render\n         (lambda () \u003ccomponent body here\u003e)\n         ...)))\n````\n\nDef-component tightens it up to this:\n\n````common-lisp\n(def-component sample-component\n  \u003ccomponent body here\u003e\n  get-initial-state\n  (lambda () ...)\n  ...)\n````\n\nThe body of the def-component macro is implicitly wrapped in a (create ...) call that, with the exception of the first item, must contain key/value pairs. The first body item will be automatically paired with the render key and enclosed in a lambda expression.\n\nA nil in the name parameter will cause def-component to return a class without attempting to save it.\n\nTo skip the implicit render body - for example, when supplying an external render function - place nil as the first item in the body.\n\n###Example code\n\nBelow is an example based on the [React tutorial](https://facebook.github.io/react/docs/tutorial.html). The javascript version is followed by the equivalent in parenscript/cl-react.\n\n````javascript\nvar data = [\n  {id: 1, author: \"Pete Hunt\", text: \"This is one comment\"},\n  {id: 2, author: \"Jordan Walke\", text: \"This is *another* comment\"}\n];\n\nvar CommentForm = React.createClass({\n  render: function() {\n    return (\n      \u003cdiv className=\"commentForm\"\u003e\n        Hello, world! I am a CommentForm.\n      \u003c/div\u003e\n    );\n  }\n});\n\nvar Comment = React.createClass({\n  rawMarkup: function() {\n    var rawMarkup = marked(this.props.children.toString(), {sanitize: true});\n    return { __html: rawMarkup };\n  },\n\n  render: function() {\n    return (\n      \u003cdiv className=\"comment\"\u003e\n        \u003ch2 className=\"commentAuthor\"\u003e\n          {this.props.author}\n        \u003c/h2\u003e\n        \u003cspan dangerouslySetInnerHTML={this.rawMarkup()} /\u003e\n      \u003c/div\u003e\n    );\n  }\n});\n\nvar CommentList = React.createClass({\n  render: function() {\n    var commentNodes = this.props.data.map(function(comment) {\n      return (\n        \u003cComment author={comment.author} key={comment.id}\u003e\n          {comment.text}\n        \u003c/Comment\u003e\n      );\n    });\n    return (\n      \u003cdiv className=\"commentList\"\u003e\n        {commentNodes}\n      \u003c/div\u003e\n    );\n  }\n});\n\nvar CommentBox = React.createClass({\n  render: function() {\n    return (\n      \u003cdiv className=\"commentBox\"\u003e\n        \u003ch1\u003eComments\u003c/h1\u003e\n        \u003cCommentList data={this.props.data} /\u003e\n        \u003cCommentForm /\u003e\n      \u003c/div\u003e\n    );\n  }\n});\n\nReactDOM.render(\n  \u003cCommentBox data={data} /\u003e,\n  document.getElementById('content')\n);\n````\n\n````common-lisp\n(var data\n     (list\n      (create id 1 author \"Peter Hunt\" text \"This is one comment\")\n      (create id 2 author \"Jordan Walke\" text \"This is *another* comment\")))\n\n(def-component -comment-form\n    (psx (:div :class-name \"commentForm\" \"Hello, world! I am a CommentForm\")))\n\n(def-component -comment\n    (psx\n     (:div :class-name \"comment\"\n           (:h2 :class-name \"commentAuthor\" (prop author))\n           (:span :dangerously-set-inner-h-t-m-l (chain this (raw-markup)))))\n  raw-markup\n  (lambda ()\n    (create __html (marked (prop children (to-string)) (create sanitize t)))))\n\n(def-component -comment-list\n    (let ((comment-nodes\n            (mapcar\n             (lambda (comment)\n               (psx (:-comment :author (@ comment author) :key (@ comment id)\n                               (@ comment text))))\n             (prop data))))\n      (psx (:div :class-name \"commentList\" comment-nodes))))\n\n(def-component -comment-box\n    (psx (:div :class-name \"commentBox\"\n               (:h1 \"Comments\")\n               (:-comment-list :data (prop data))\n               (:-comment-form))))\n\n(render (psx (:-comment-box :data data))\n        (chain document (get-element-by-id \"content\")))\n````\n","funding_links":[],"categories":["Common Lisp","Interfaces to other package managers"],"sub_categories":["Isomorphic web frameworks"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhelmutkian%2Fcl-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhelmutkian%2Fcl-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhelmutkian%2Fcl-react/lists"}