elm-pages 3.0.0-beta.4 → 3.0.0-beta.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +10 -1
  2. package/adapter/netlify.js +207 -0
  3. package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2678 -2725
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
  6. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
  7. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  8. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  9. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  10. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
  11. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1447 -342
  12. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +17004 -13817
  13. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  14. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
  15. package/generator/dead-code-review/elm.json +9 -7
  16. package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +59 -10
  17. package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +52 -36
  18. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmi +0 -0
  19. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmo +0 -0
  20. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmi +0 -0
  21. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmo +0 -0
  22. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  23. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  24. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  25. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
  26. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1447 -342
  27. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +25025 -21739
  28. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  29. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
  30. package/generator/review/elm.json +10 -10
  31. package/generator/src/RouteBuilder.elm +115 -109
  32. package/generator/src/SharedTemplate.elm +3 -2
  33. package/generator/src/SiteConfig.elm +3 -2
  34. package/generator/src/basepath-middleware.js +3 -3
  35. package/generator/src/build.js +209 -92
  36. package/generator/src/cli.js +292 -88
  37. package/generator/src/codegen.js +29 -27
  38. package/generator/src/compatibility-key.js +3 -0
  39. package/generator/src/compile-elm.js +43 -26
  40. package/generator/src/config.js +39 -0
  41. package/generator/src/copy-dir.js +2 -2
  42. package/generator/src/dev-server.js +176 -138
  43. package/generator/src/dir-helpers.js +9 -26
  44. package/generator/src/elm-codegen.js +5 -4
  45. package/generator/src/elm-file-constants.js +2 -3
  46. package/generator/src/error-formatter.js +12 -11
  47. package/generator/src/file-helpers.js +3 -4
  48. package/generator/src/generate-template-module-connector.js +23 -23
  49. package/generator/src/init.js +9 -8
  50. package/generator/src/pre-render-html.js +39 -28
  51. package/generator/src/render-test.js +109 -0
  52. package/generator/src/render-worker.js +25 -28
  53. package/generator/src/render.js +321 -142
  54. package/generator/src/request-cache.js +265 -162
  55. package/generator/src/resolve-elm-module.js +64 -0
  56. package/generator/src/rewrite-client-elm-json.js +6 -5
  57. package/generator/src/rewrite-elm-json-help.js +56 -0
  58. package/generator/src/rewrite-elm-json.js +17 -7
  59. package/generator/src/route-codegen-helpers.js +16 -31
  60. package/generator/src/seo-renderer.js +12 -7
  61. package/generator/src/vite-utils.js +77 -0
  62. package/generator/static-code/elm-pages.js +10 -0
  63. package/generator/static-code/hmr.js +79 -13
  64. package/generator/template/app/Api.elm +6 -5
  65. package/generator/template/app/Effect.elm +123 -0
  66. package/generator/template/app/ErrorPage.elm +37 -6
  67. package/generator/template/app/Route/Index.elm +17 -10
  68. package/generator/template/app/Shared.elm +24 -47
  69. package/generator/template/app/Site.elm +19 -6
  70. package/generator/template/app/View.elm +1 -8
  71. package/generator/template/elm-tooling.json +0 -3
  72. package/generator/template/elm.json +32 -24
  73. package/generator/template/package.json +10 -4
  74. package/package.json +30 -27
  75. package/src/ApiRoute.elm +199 -61
  76. package/src/BackendTask/Custom.elm +325 -0
  77. package/src/BackendTask/Env.elm +90 -0
  78. package/src/{DataSource → BackendTask}/File.elm +171 -56
  79. package/src/{DataSource → BackendTask}/Glob.elm +136 -125
  80. package/src/BackendTask/Http.elm +679 -0
  81. package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
  82. package/src/BackendTask/Internal/Request.elm +69 -0
  83. package/src/BackendTask/Random.elm +79 -0
  84. package/src/BackendTask/Time.elm +47 -0
  85. package/src/BackendTask.elm +537 -0
  86. package/src/FatalError.elm +90 -0
  87. package/src/Head.elm +237 -7
  88. package/src/HtmlPrinter.elm +7 -3
  89. package/src/Internal/ApiRoute.elm +7 -5
  90. package/src/PageServerResponse.elm +6 -1
  91. package/src/Pages/Form.elm +229 -0
  92. package/src/Pages/GeneratorProgramConfig.elm +15 -0
  93. package/src/Pages/Internal/FatalError.elm +5 -0
  94. package/src/Pages/Internal/Msg.elm +93 -0
  95. package/src/Pages/Internal/Platform/Cli.elm +612 -763
  96. package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
  97. package/src/Pages/Internal/Platform/Effect.elm +1 -2
  98. package/src/Pages/Internal/Platform/GeneratorApplication.elm +379 -0
  99. package/src/Pages/Internal/Platform/StaticResponses.elm +65 -276
  100. package/src/Pages/Internal/Platform/ToJsPayload.elm +6 -9
  101. package/src/Pages/Internal/Platform.elm +327 -194
  102. package/src/Pages/Internal/Script.elm +17 -0
  103. package/src/Pages/Internal/StaticHttpBody.elm +35 -1
  104. package/src/Pages/Manifest.elm +29 -4
  105. package/src/Pages/PageUrl.elm +23 -9
  106. package/src/Pages/ProgramConfig.elm +26 -15
  107. package/src/Pages/Script.elm +109 -0
  108. package/src/Pages/SiteConfig.elm +3 -2
  109. package/src/Pages/StaticHttp/Request.elm +2 -2
  110. package/src/Pages/StaticHttpRequest.elm +23 -99
  111. package/src/Pages/Transition.elm +12 -3
  112. package/src/PagesMsg.elm +82 -0
  113. package/src/Path.elm +16 -19
  114. package/src/QueryParams.elm +21 -172
  115. package/src/RequestsAndPending.elm +37 -20
  116. package/src/Result/Extra.elm +26 -0
  117. package/src/Scaffold/Form.elm +546 -0
  118. package/src/Scaffold/Route.elm +1402 -0
  119. package/src/Server/Request.elm +73 -72
  120. package/src/Server/Session.elm +62 -42
  121. package/src/Server/SetCookie.elm +12 -4
  122. package/src/Stub.elm +53 -0
  123. package/src/Test/Html/Internal/ElmHtml/ToString.elm +8 -9
  124. package/src/DataSource/Env.elm +0 -38
  125. package/src/DataSource/Http.elm +0 -446
  126. package/src/DataSource/Internal/Request.elm +0 -20
  127. package/src/DataSource/Port.elm +0 -90
  128. package/src/DataSource.elm +0 -538
  129. package/src/Form/Field.elm +0 -717
  130. package/src/Form/FieldStatus.elm +0 -36
  131. package/src/Form/FieldView.elm +0 -417
  132. package/src/Form/FormData.elm +0 -22
  133. package/src/Form/Validation.elm +0 -391
  134. package/src/Form/Value.elm +0 -118
  135. package/src/Form.elm +0 -1683
  136. package/src/FormDecoder.elm +0 -102
  137. package/src/Pages/FormState.elm +0 -256
  138. package/src/Pages/Generate.elm +0 -800
  139. package/src/Pages/Internal/Form.elm +0 -17
  140. package/src/Pages/Msg.elm +0 -79
package/src/Head.elm CHANGED
@@ -1,6 +1,7 @@
1
1
  module Head exposing
2
2
  ( Tag, metaName, metaProperty, metaRedirect
3
3
  , rssLink, sitemapLink, rootLanguage, manifestLink
4
+ , nonLoadingNode
4
5
  , structuredData
5
6
  , AttributeValue
6
7
  , currentPageFullUrl, urlAttribute, raw
@@ -8,18 +9,124 @@ module Head exposing
8
9
  , toJson, canonicalLink
9
10
  )
10
11
 
11
- {-| This module contains low-level functions for building up
12
- values that will be rendered into the page's `<head>` tag
13
- when you run `elm-pages build`. Most likely the `Head.Seo` module
14
- will do everything you need out of the box, and you will just need to import `Head`
15
- so you can use the `Tag` type in your type annotations.
12
+ {-| This module contains functions for building up
13
+ tags with metadata that will be rendered into the page's `<head>` tag
14
+ when your page is pre-rendered (or server-rendered, in the case of your server-rendered Route Modules). See also [`Head.Seo`](Head-Seo),
15
+ which has some helper functions for defining OpenGraph and Twitter tags.
16
16
 
17
- But this module might be useful if you have a special use case, or if you are
18
- writing a plugin package to extend `elm-pages`.
17
+ One of the unique benefits of using `elm-pages` is that all of your routes (both pre-rendered and server-rendered) fully
18
+ render the HTML of your page. That includes the full initial `view` (with the BackendTask resolved, and the `Model` from `init`).
19
+ The HTML response also includes all of the `Head` tags, which are defined in two places:
20
+
21
+ 1. `app/Site.elm` - there is a `head` definition in `Site.elm` where you define global head tags that will be included on every rendered page.
22
+
23
+ 2. In each Route Module - there is a `head` function where you have access to both the resolved `BackendTask` and the `RouteParams` for the page and can return head tags based on that.
24
+
25
+ Here is a common set of global head tags that we can define in `Site.elm`:
26
+
27
+ module Site exposing (canonicalUrl, config)
28
+
29
+ import BackendTask exposing (BackendTask)
30
+ import Head
31
+ import MimeType
32
+ import SiteConfig exposing (SiteConfig)
33
+
34
+ config : SiteConfig
35
+ config =
36
+ { canonicalUrl = "<https://elm-pages.com">
37
+ , head = head
38
+ }
39
+
40
+ head : BackendTask (List Head.Tag)
41
+ head =
42
+ [ Head.metaName "viewport" (Head.raw "width=device-width,initial-scale=1")
43
+ , Head.metaName "mobile-web-app-capable" (Head.raw "yes")
44
+ , Head.metaName "theme-color" (Head.raw "#ffffff")
45
+ , Head.metaName "apple-mobile-web-app-capable" (Head.raw "yes")
46
+ , Head.metaName "apple-mobile-web-app-status-bar-style" (Head.raw "black-translucent")
47
+ , Head.icon [ ( 32, 32 ) ] MimeType.Png (cloudinaryIcon MimeType.Png 32)
48
+ , Head.icon [ ( 16, 16 ) ] MimeType.Png (cloudinaryIcon MimeType.Png 16)
49
+ , Head.appleTouchIcon (Just 180) (cloudinaryIcon MimeType.Png 180)
50
+ , Head.appleTouchIcon (Just 192) (cloudinaryIcon MimeType.Png 192)
51
+ ]
52
+ |> BackendTask.succeed
53
+
54
+ And here is a `head` function for a Route Module for a blog post. Note that we have access to our `BackendTask` Data and
55
+ are using it to populate article metadata like the article's image, publish date, etc.
56
+
57
+ import Article
58
+ import BackendTask
59
+ import Date
60
+ import Head
61
+ import Head.Seo
62
+ import Path
63
+ import Route exposing (Route)
64
+ import RouteBuilder exposing (App, StatelessRoute)
65
+
66
+ type alias RouteParams =
67
+ { slug : String }
68
+
69
+ type alias Data =
70
+ { metadata : ArticleMetadata
71
+ , body : List Markdown.Block.Block
72
+ }
73
+
74
+ route : StatelessRoute RouteParams Data ActionData
75
+ route =
76
+ RouteBuilder.preRender
77
+ { data = data
78
+ , head = head
79
+ , pages = pages
80
+ }
81
+ |> RouteBuilder.buildNoState { view = view }
82
+
83
+ head :
84
+ App Data ActionData RouteParams
85
+ -> List Head.Tag
86
+ head static =
87
+ let
88
+ metadata =
89
+ static.data.metadata
90
+ in
91
+ Head.Seo.summaryLarge
92
+ { canonicalUrlOverride = Nothing
93
+ , siteName = "elm-pages"
94
+ , image =
95
+ { url = metadata.image
96
+ , alt = metadata.description
97
+ , dimensions = Nothing
98
+ , mimeType = Nothing
99
+ }
100
+ , description = metadata.description
101
+ , locale = Nothing
102
+ , title = metadata.title
103
+ }
104
+ |> Head.Seo.article
105
+ { tags = []
106
+ , section = Nothing
107
+ , publishedTime = Just (DateOrDateTime.Date metadata.published)
108
+ , modifiedTime = Nothing
109
+ , expirationTime = Nothing
110
+ }
111
+
112
+
113
+ ## Why is pre-rendered HTML important? Does it still matter for SEO?
114
+
115
+ Many search engines are able to execute JavaScript now. However, not all are, and even with crawlers like Google, there
116
+ is a longer lead time for your pages to be indexed when you have HTML with a blank page that is only visible after the JavaScript executes.
117
+
118
+ But most importantly, many tools that unfurl links will not execute JavaScript at all, but rather simply do a simple pass to parse your `<head>` tags.
119
+ It is not viable or reliable to add `<head>` tags for metadata on the client-side, it must be present in the initial HTML payload. Otherwise you may not
120
+ get unfurling preview content when you share a link to your site on Slack, Twitter, etc.
121
+
122
+
123
+ ## Building up Head Tags
19
124
 
20
125
  @docs Tag, metaName, metaProperty, metaRedirect
21
126
  @docs rssLink, sitemapLink, rootLanguage, manifestLink
22
127
 
128
+ @docs nonLoadingNode
129
+
23
130
 
24
131
  ## Structured Data
25
132
 
@@ -45,9 +152,11 @@ writing a plugin package to extend `elm-pages`.
45
152
 
46
153
  import Json.Encode
47
154
  import LanguageTag exposing (LanguageTag)
155
+ import List.Extra
48
156
  import MimeType
49
157
  import Pages.Internal.String as String
50
158
  import Pages.Url
159
+ import Regex
51
160
 
52
161
 
53
162
  {-| Values that can be passed to the generated `Pages.application` config
@@ -57,6 +166,7 @@ type Tag
57
166
  = Tag Details
58
167
  | StructuredData Json.Encode.Value
59
168
  | RootModifier String String
169
+ | Stripped String
60
170
 
61
171
 
62
172
  type alias Details =
@@ -211,6 +321,120 @@ canonicalLink maybePath =
211
321
  ]
212
322
 
213
323
 
324
+ {-| Escape hatch for any head tags that don't have high-level helpers. This lets you build arbitrary head nodes as long as they
325
+ are not loading or preloading directives.
326
+
327
+ Tags that do loading/pre-loading will not work from this function. `elm-pages` uses ViteJS for loading assets like
328
+ script tags, stylesheets, fonts, etc., and allows you to customize which assets to preload and how through the elm-pages.config.mjs file.
329
+ See the full discussion of the design in [#339](https://github.com/dillonkearns/elm-pages/discussions/339).
330
+
331
+ So for example the following tags would _not_ load if defined through `nonLoadingNode`, and would instead need to be registered through Vite:
332
+
333
+ - `<script src="...">`
334
+ - `<link href="/style.css">`
335
+ - `<link rel="preload">`
336
+
337
+ The following tag would successfully render as it is a non-loading tag:
338
+
339
+ Head.nonLoadingNode "link"
340
+ [ ( "rel", Head.raw "alternate" )
341
+ , ( "type", Head.raw "application/atom+xml" )
342
+ , ( "title", Head.raw "News" )
343
+ , ( "href", Head.raw "/news/atom" )
344
+ ]
345
+
346
+ Renders the head tag:
347
+
348
+ `<link rel="alternate" type="application/atom+xml" title="News" href="/news/atom">`
349
+
350
+ -}
351
+ nonLoadingNode : String -> List ( String, AttributeValue ) -> Tag
352
+ nonLoadingNode nodeName attributes =
353
+ let
354
+ relTag : Maybe AttributeValue
355
+ relTag =
356
+ attributes
357
+ |> List.Extra.find (\( key, _ ) -> key == "rel")
358
+ |> Maybe.map Tuple.second
359
+
360
+ isPreloadDirective : Bool
361
+ isPreloadDirective =
362
+ case relTag of
363
+ Just (Raw rel) ->
364
+ let
365
+ isLinkTag : Bool
366
+ isLinkTag =
367
+ nodeName |> matchesKeyword "link"
368
+ in
369
+ isLinkTag
370
+ && (rel
371
+ |> matchesOneKeyword
372
+ [ "preload"
373
+ , "modulepreload"
374
+ , "preconnect"
375
+ , "dns-prefetch"
376
+ , "stylesheet"
377
+ ]
378
+ )
379
+
380
+ _ ->
381
+ False
382
+ in
383
+ if
384
+ (nodeName |> matchesKeyword "script")
385
+ || isPreloadDirective
386
+ then
387
+ Stripped
388
+ ("<"
389
+ ++ nodeName
390
+ ++ " "
391
+ ++ (attributes
392
+ |> List.map
393
+ (\( name, value ) ->
394
+ name
395
+ ++ "=\""
396
+ ++ ((case value of
397
+ Raw rawValue ->
398
+ rawValue
399
+
400
+ _ ->
401
+ "<internals>"
402
+ )
403
+ ++ "\""
404
+ )
405
+ )
406
+ |> String.join " "
407
+ )
408
+ ++ " />"
409
+ )
410
+
411
+ else
412
+ node nodeName attributes
413
+
414
+
415
+ matchesOneKeyword : List String -> String -> Bool
416
+ matchesOneKeyword keywords string =
417
+ List.any
418
+ (\keyword -> string |> matchesKeyword keyword)
419
+ keywords
420
+
421
+
422
+ matchesKeyword : String -> String -> Bool
423
+ matchesKeyword regex string =
424
+ string |> matchesRegex ("^\\s*" ++ regex ++ "\\s*$")
425
+
426
+
427
+ matchesRegex : String -> String -> Bool
428
+ matchesRegex regex string =
429
+ string
430
+ |> Regex.contains
431
+ (Regex.fromStringWith
432
+ { caseInsensitive = True, multiline = True }
433
+ regex
434
+ |> Maybe.withDefault Regex.never
435
+ )
436
+
437
+
214
438
  {-| Let's you link to your manifest.json file, see <https://developer.mozilla.org/en-US/docs/Web/Manifest#deploying_a_manifest>.
215
439
  -}
216
440
  manifestLink : String -> Tag
@@ -443,6 +667,12 @@ toJson canonicalSiteUrl currentPagePath tag =
443
667
  , ( "keyValuePair", Json.Encode.list Json.Encode.string [ key, value ] )
444
668
  ]
445
669
 
670
+ Stripped message ->
671
+ Json.Encode.object
672
+ [ ( "type", Json.Encode.string "stripped" )
673
+ , ( "message", Json.Encode.string message )
674
+ ]
675
+
446
676
 
447
677
  encodeProperty : String -> String -> ( String, AttributeValue ) -> Json.Encode.Value
448
678
  encodeProperty canonicalSiteUrl currentPagePath ( name, value ) =
@@ -8,15 +8,19 @@ import Test.Html.Internal.ElmHtml.ToString exposing (defaultFormatOptions, nodeT
8
8
  import VirtualDom
9
9
 
10
10
 
11
- htmlToString : Html msg -> String
12
- htmlToString viewHtml =
11
+ htmlToString : Maybe { indent : Int, newLines : Bool } -> Html msg -> String
12
+ htmlToString formatOptions viewHtml =
13
13
  case
14
14
  Decode.decodeValue
15
15
  (decodeElmHtml (\_ _ -> VirtualDom.Normal (Decode.succeed ())))
16
16
  (asJsonView viewHtml)
17
17
  of
18
18
  Ok str ->
19
- nodeToStringWithOptions defaultFormatOptions str
19
+ nodeToStringWithOptions
20
+ (formatOptions
21
+ |> Maybe.withDefault defaultFormatOptions
22
+ )
23
+ str
20
24
 
21
25
  Err err ->
22
26
  "Error pre-rendering HTML in HtmlPrinter.elm: " ++ Decode.errorToString err
@@ -8,8 +8,10 @@ module Internal.ApiRoute exposing
8
8
  , withRoutes
9
9
  )
10
10
 
11
- import DataSource exposing (DataSource)
11
+ import BackendTask exposing (BackendTask)
12
+ import FatalError exposing (FatalError)
12
13
  import Head
14
+ import Json.Decode
13
15
  import Pattern exposing (Pattern)
14
16
  import Regex exposing (Regex)
15
17
 
@@ -44,12 +46,12 @@ tryMatchDone path (ApiRoute handler) =
44
46
  type ApiRoute response
45
47
  = ApiRoute
46
48
  { regex : Regex
47
- , matchesToResponse : String -> DataSource (Maybe response)
48
- , buildTimeRoutes : DataSource (List String)
49
- , handleRoute : String -> DataSource Bool
49
+ , matchesToResponse : Json.Decode.Value -> String -> BackendTask FatalError (Maybe response)
50
+ , buildTimeRoutes : BackendTask FatalError (List String)
51
+ , handleRoute : String -> BackendTask FatalError Bool
50
52
  , pattern : Pattern
51
53
  , kind : String
52
- , globalHeadTags : Maybe (DataSource (List Head.Tag))
54
+ , globalHeadTags : Maybe (BackendTask FatalError (List Head.Tag))
53
55
  }
54
56
 
55
57
 
@@ -15,7 +15,12 @@ type PageServerResponse data error
15
15
  | ErrorPage error { headers : List ( String, String ) }
16
16
 
17
17
 
18
- toRedirect : Response -> Maybe { statusCode : Int, location : String }
18
+ toRedirect :
19
+ { response
20
+ | statusCode : Int
21
+ , headers : List ( String, String )
22
+ }
23
+ -> Maybe { statusCode : Int, location : String }
19
24
  toRedirect response =
20
25
  response.headers
21
26
  |> Dict.fromList
@@ -0,0 +1,229 @@
1
+ module Pages.Form exposing
2
+ ( Strategy(..), renderHtml, renderStyledHtml
3
+ , FormWithServerValidations, Handler
4
+ )
5
+
6
+ {-|
7
+
8
+ @docs Strategy, renderHtml, renderStyledHtml
9
+
10
+ @docs FormWithServerValidations, Handler
11
+
12
+ -}
13
+
14
+ import BackendTask exposing (BackendTask)
15
+ import Dict exposing (Dict)
16
+ import FatalError exposing (FatalError)
17
+ import Form
18
+ import Form.Handler
19
+ import Form.Validation exposing (Validation)
20
+ import Html
21
+ import Html.Styled
22
+ import Pages.Internal.Msg
23
+ import Pages.Transition
24
+ import PagesMsg exposing (PagesMsg)
25
+
26
+
27
+ {-| -}
28
+ type alias FormWithServerValidations error combined input view =
29
+ Form.Form
30
+ error
31
+ { combine :
32
+ Validation
33
+ error
34
+ (BackendTask FatalError (Validation error combined Never Never))
35
+ Never
36
+ Never
37
+ , view : Form.Context error input -> view
38
+ }
39
+ (BackendTask FatalError (Validation error combined Never Never))
40
+ input
41
+
42
+
43
+ {-| -}
44
+ type alias Handler error combined =
45
+ Form.Handler.Handler error (BackendTask FatalError (Validation error combined Never Never))
46
+
47
+
48
+ {-| -}
49
+ type Strategy
50
+ = Parallel
51
+ | Serial
52
+
53
+
54
+ {-| -}
55
+ renderHtml :
56
+ List (Html.Attribute (PagesMsg userMsg))
57
+ -> Strategy
58
+ -> Form.Options error parsed input userMsg
59
+ ->
60
+ { --path : Path
61
+ --, url : Maybe PageUrl
62
+ --, action : Maybe action
63
+ app
64
+ | pageFormState : Form.Model
65
+ , transition : Maybe Pages.Transition.Transition
66
+ , fetchers : Dict String (Pages.Transition.FetcherState (Maybe action))
67
+ }
68
+ -> Form.Form error { combine : Validation error parsed named constraints, view : Form.Context error input -> List (Html.Html (PagesMsg userMsg)) } parsed input
69
+ -> Html.Html (PagesMsg userMsg)
70
+ renderHtml attrs strategy options_ app form_ =
71
+ form_
72
+ |> Form.renderHtml
73
+ { state = app.pageFormState
74
+ , submitting =
75
+ (case app.fetchers |> Dict.get options_.id of
76
+ Just { status } ->
77
+ case status of
78
+ Pages.Transition.FetcherComplete _ ->
79
+ False
80
+
81
+ Pages.Transition.FetcherSubmitting ->
82
+ True
83
+
84
+ Pages.Transition.FetcherReloading _ ->
85
+ True
86
+
87
+ Nothing ->
88
+ False
89
+ )
90
+ || (case app.transition of
91
+ Just (Pages.Transition.Submitting formData) ->
92
+ formData.id == Just options_.id
93
+
94
+ Just (Pages.Transition.LoadAfterSubmit submitData _ _) ->
95
+ submitData.id == Just options_.id
96
+
97
+ Just (Pages.Transition.Loading _ _) ->
98
+ False
99
+
100
+ Nothing ->
101
+ False
102
+ )
103
+ , toMsg = Pages.Internal.Msg.FormMsg
104
+ }
105
+ { id = options_.id
106
+ , method = options_.method
107
+ , input = options_.input
108
+ , serverResponse = options_.serverResponse
109
+ , action = options_.action
110
+ , onSubmit =
111
+ Just
112
+ (\submission ->
113
+ case submission.parsed of
114
+ Form.Valid _ ->
115
+ Pages.Internal.Msg.Submit
116
+ { useFetcher = strategy == Parallel
117
+ , action = submission.action
118
+ , fields = submission.fields
119
+ , method = submission.method
120
+ , msg =
121
+ options_.onSubmit
122
+ |> Maybe.map
123
+ (\onSubmit -> onSubmit submission)
124
+ , id = options_.id
125
+ , valid = True
126
+ }
127
+
128
+ Form.Invalid _ _ ->
129
+ Pages.Internal.Msg.Submit
130
+ { useFetcher = strategy == Parallel
131
+ , action = submission.action
132
+ , method = submission.method
133
+ , fields = submission.fields
134
+ , msg = options_.onSubmit |> Maybe.map (\onSubmit -> onSubmit submission)
135
+ , id = options_.id
136
+ , valid = False
137
+ }
138
+ )
139
+ }
140
+ attrs
141
+
142
+
143
+ {-| -}
144
+ renderStyledHtml :
145
+ List (Html.Styled.Attribute (PagesMsg userMsg))
146
+ -> Strategy
147
+ -> Form.Options error parsed input userMsg
148
+ ->
149
+ { --path : Path
150
+ --, url : Maybe PageUrl
151
+ --, action : Maybe action
152
+ app
153
+ | pageFormState : Form.Model
154
+ , transition : Maybe Pages.Transition.Transition
155
+ , fetchers : Dict String (Pages.Transition.FetcherState (Maybe action))
156
+ }
157
+ -> Form.Form error { combine : Validation error parsed named constraints, view : Form.Context error input -> List (Html.Styled.Html (PagesMsg userMsg)) } parsed input
158
+ -> Html.Styled.Html (PagesMsg userMsg)
159
+ renderStyledHtml attrs strategy options_ app form_ =
160
+ form_
161
+ |> Form.renderStyledHtml
162
+ { state = app.pageFormState
163
+ , toMsg = Pages.Internal.Msg.FormMsg
164
+ , submitting =
165
+ (case app.fetchers |> Dict.get options_.id of
166
+ Just { status } ->
167
+ case status of
168
+ Pages.Transition.FetcherComplete _ ->
169
+ False
170
+
171
+ Pages.Transition.FetcherSubmitting ->
172
+ True
173
+
174
+ Pages.Transition.FetcherReloading _ ->
175
+ True
176
+
177
+ Nothing ->
178
+ False
179
+ )
180
+ || (case app.transition of
181
+ Just (Pages.Transition.Submitting formData) ->
182
+ formData.id == Just options_.id
183
+
184
+ Just (Pages.Transition.LoadAfterSubmit submitData _ _) ->
185
+ submitData.id == Just options_.id
186
+
187
+ Just (Pages.Transition.Loading _ _) ->
188
+ False
189
+
190
+ Nothing ->
191
+ False
192
+ )
193
+ }
194
+ { id = options_.id
195
+ , method = options_.method
196
+ , input = options_.input
197
+ , serverResponse = options_.serverResponse
198
+ , action = options_.action
199
+ , onSubmit =
200
+ Just
201
+ (\submission ->
202
+ case submission.parsed of
203
+ Form.Valid _ ->
204
+ Pages.Internal.Msg.Submit
205
+ { useFetcher = strategy == Parallel
206
+ , action = submission.action
207
+ , fields = submission.fields
208
+ , method = submission.method
209
+ , msg =
210
+ options_.onSubmit
211
+ |> Maybe.map
212
+ (\onSubmit -> onSubmit submission)
213
+ , id = options_.id
214
+ , valid = True
215
+ }
216
+
217
+ Form.Invalid _ _ ->
218
+ Pages.Internal.Msg.Submit
219
+ { useFetcher = strategy == Parallel
220
+ , action = submission.action
221
+ , fields = submission.fields
222
+ , method = submission.method
223
+ , msg = options_.onSubmit |> Maybe.map (\onSubmit -> onSubmit submission)
224
+ , id = options_.id
225
+ , valid = False
226
+ }
227
+ )
228
+ }
229
+ attrs
@@ -0,0 +1,15 @@
1
+ module Pages.GeneratorProgramConfig exposing (GeneratorProgramConfig)
2
+
3
+ import Json.Decode as Decode
4
+ import Json.Encode
5
+ import Pages.Internal.Platform.ToJsPayload
6
+ import Pages.Script exposing (Script)
7
+
8
+
9
+ type alias GeneratorProgramConfig =
10
+ { data : Script
11
+ , toJsPort : Json.Encode.Value -> Cmd Never
12
+ , fromJsPort : Sub Decode.Value
13
+ , gotBatchSub : Sub Decode.Value
14
+ , sendPageData : Pages.Internal.Platform.ToJsPayload.NewThingForPort -> Cmd Never
15
+ }
@@ -0,0 +1,5 @@
1
+ module Pages.Internal.FatalError exposing (FatalError(..))
2
+
3
+
4
+ type FatalError
5
+ = FatalError { title : String, body : String }