@axel669/zephyr 0.3.6 → 0.4.4-beta.0

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 (78) hide show
  1. package/package.json +12 -5
  2. package/src/async/button.svelte +16 -8
  3. package/src/composed/data-table/th.svelte +5 -5
  4. package/src/composed/data-table.svelte +6 -5
  5. package/src/composed/form.svelte +60 -0
  6. package/src/composed/table-functions.js +3 -1
  7. package/src/composed/toast/message.svelte +15 -38
  8. package/src/control/button.svelte +1 -1
  9. package/src/control/input.svelte +89 -109
  10. package/src/control/label.svelte +1 -1
  11. package/src/control/link.svelte +32 -32
  12. package/src/control/radio-group.svelte +21 -0
  13. package/src/control/select.svelte +5 -5
  14. package/src/control/tabs.svelte +9 -21
  15. package/src/control/toggle.svelte +2 -2
  16. package/src/data-display/avatar.svelte +4 -1
  17. package/src/data-display/badge.svelte +1 -1
  18. package/src/data-display/chip.svelte +1 -1
  19. package/src/data-display/popover.svelte +25 -25
  20. package/src/data-display/progress.svelte +27 -27
  21. package/src/data-display/table.svelte +1 -1
  22. package/src/dialogs/confirm.svelte +3 -3
  23. package/src/hash.js +14 -14
  24. package/src/index.mjs +11 -1
  25. package/src/info/icon.svelte +1 -1
  26. package/src/info/notification.svelte +28 -16
  27. package/src/info/titlebar.svelte +22 -5
  28. package/src/layout/dialog.svelte +1 -1
  29. package/src/layout/drawer.svelte +49 -49
  30. package/src/layout/flex.svelte +0 -4
  31. package/src/layout/grid.svelte +4 -4
  32. package/src/layout/paper.svelte +56 -47
  33. package/src/routing/route.svelte +48 -0
  34. package/src/routing/routing.js +62 -0
  35. package/src/routing/title.svelte +26 -0
  36. package/src/spinner/circle-spinner.svelte +2 -1
  37. package/src/spinner/hexagon-spinner.svelte +2 -1
  38. package/src/text.svelte +2 -4
  39. package/src/wsx.mjs +25 -24
  40. package/src/async/button.md +0 -27
  41. package/src/async/load-zone.md +0 -42
  42. package/src/composed/data-table/th.md +0 -21
  43. package/src/composed/data-table.md +0 -86
  44. package/src/composed/entry-button.md +0 -44
  45. package/src/composed/toast.md +0 -45
  46. package/src/control/button.md +0 -41
  47. package/src/control/input.md +0 -87
  48. package/src/control/label.md +0 -48
  49. package/src/control/link.md +0 -50
  50. package/src/control/radio.md +0 -58
  51. package/src/control/radio.svelte +0 -28
  52. package/src/control/select.md +0 -70
  53. package/src/control/tabs.md +0 -47
  54. package/src/control/toggle.md +0 -61
  55. package/src/data-display/avatar.md +0 -36
  56. package/src/data-display/badge.md +0 -30
  57. package/src/data-display/chip.md +0 -36
  58. package/src/data-display/details.md +0 -42
  59. package/src/data-display/popover.md +0 -32
  60. package/src/data-display/progress.md +0 -46
  61. package/src/data-display/table.md +0 -59
  62. package/src/data-display/tooltip.md +0 -29
  63. package/src/dialogs/alert.md +0 -42
  64. package/src/dialogs/confirm.md +0 -56
  65. package/src/functions.md +0 -108
  66. package/src/info/icon.md +0 -21
  67. package/src/info/notification.md +0 -36
  68. package/src/info/titlebar.md +0 -75
  69. package/src/info/toaster.md +0 -26
  70. package/src/layout/dialog.md +0 -43
  71. package/src/layout/drawer.md +0 -70
  72. package/src/layout/flex.md +0 -43
  73. package/src/layout/grid.md +0 -61
  74. package/src/layout/modal.md +0 -50
  75. package/src/layout/paper.md +0 -94
  76. package/src/layout/screen.md +0 -33
  77. package/src/spinner/spinners.md +0 -22
  78. package/src/text.md +0 -34
@@ -0,0 +1,48 @@
1
+ <script context="module">
2
+ const urlPattern = (path, exact) => {
3
+ const regexSource = path.replace(
4
+ /:([\w\-]+)/g,
5
+ (_, name) => `\(?<${name}>[\\w\\-\\%]+\)`
6
+ )
7
+ if (exact === true) {
8
+ return new RegExp(`(?<_path>^${regexSource})$`)
9
+ }
10
+ return new RegExp(`(?<_path>^${regexSource})(((?<=\\/)[\\w\\-\\%])|\\/|$)`)
11
+ }
12
+ </script>
13
+
14
+ <script>
15
+ import { getContext, setContext } from "svelte"
16
+
17
+ import { ctx, resolve, route } from "./routing.js"
18
+
19
+ export let path = ""
20
+ export let component = null
21
+ export let props = {}
22
+ export let exact = false
23
+
24
+ const parent = getContext(ctx.parent) ?? "/"
25
+ const fullPath = resolve(parent, path)
26
+
27
+ setContext(ctx.parent, fullPath)
28
+ $: pattern = urlPattern(fullPath, exact)
29
+ $: match = $route.match(pattern)
30
+ $: routeParams = Object.fromEntries(
31
+ Object.entries({ ...match?.groups }).map(
32
+ ([key, value]) => [key, decodeURIComponent(value)]
33
+ )
34
+ )
35
+ $: routeInfo = {
36
+ params: routeParams,
37
+ match: routeParams._path,
38
+ route: $route,
39
+ }
40
+ </script>
41
+
42
+ {#if match !== null}
43
+ {#key routeParams._path}
44
+ <slot {routeInfo}>
45
+ <svelte:component this={component} {...props} {routeInfo} />
46
+ </slot>
47
+ {/key}
48
+ {/if}
@@ -0,0 +1,62 @@
1
+ import { onMount, getContext } from "svelte"
2
+ import { writable, derived } from "svelte/store"
3
+
4
+ import { hash } from "../hash.js"
5
+
6
+ export const route = derived(
7
+ hash,
8
+ hash => {
9
+ if (hash.startsWith("/") === false) {
10
+ return `/${hash}`
11
+ }
12
+ return hash
13
+ }
14
+ )
15
+
16
+ export const ctx = {
17
+ router: Symbol("Router Context"),
18
+ parent: Symbol("Route Parent"),
19
+ layout: Symbol("Layout Context"),
20
+ }
21
+ export const resolve = (base, part) => {
22
+ if (part === "" || part === "/") {
23
+ return base
24
+ }
25
+ if (base === "/" || base === undefined) {
26
+ return `/${part}`
27
+ }
28
+ if (part.startsWith("/") === true) {
29
+ return `${base}${part}`
30
+ }
31
+ return `${base}/${part}`
32
+ }
33
+ export const relpath = (path) => {
34
+ const base = getContext(ctx.parent)
35
+ return `#${resolve(base, path)}`
36
+ }
37
+
38
+ const emptyStack = Symbol("empty stack")
39
+ export const stackStore = (initial = stackStore.empty) => {
40
+ const stack = [writable(initial)]
41
+ const current = writable(initial)
42
+ let attachment = stack[0].subscribe(current.set)
43
+
44
+ return {
45
+ subscribe: current.subscribe,
46
+ push: (initial) => {
47
+ const item = writable(initial)
48
+ onMount(() => {
49
+ stack.push(item)
50
+ attachment()
51
+ attachment = item.subscribe(current.set)
52
+ return () => {
53
+ stack.pop()
54
+ attachment()
55
+ attachment = stack[stack.length - 1].subscribe(current.set)
56
+ }
57
+ })
58
+ return item
59
+ }
60
+ }
61
+ }
62
+ stackStore.empty = emptyStack
@@ -0,0 +1,26 @@
1
+ <script context="module">
2
+ import { writable } from "svelte/store"
3
+
4
+ import { stackStore } from "./routing.js"
5
+
6
+ // const stack = writable([])
7
+ const stack = stackStore()
8
+
9
+ const updateTitle = (format, data) => {
10
+ if (format === null || data === stackStore.empty) {
11
+ return
12
+ }
13
+
14
+ document.title = format(data)
15
+ }
16
+ </script>
17
+
18
+ <script>
19
+ import { onMount } from "svelte"
20
+ export let data = ""
21
+ export let format = null
22
+
23
+ stack.push(data)
24
+
25
+ $: updateTitle(format, $stack)
26
+ </script>
@@ -7,9 +7,10 @@
7
7
  export let color = "@primary"
8
8
 
9
9
  $: wind = {
10
+ ...$$restProps,
10
11
  "@size": size,
11
12
  "$color": color,
12
13
  }
13
14
  </script>
14
15
 
15
- <ws-circle-spinner use:wsx={wind} />
16
+ <ws-circle-spinner use:wsx={wind} style="aspect-ratio: 1 / 1;" />
@@ -7,9 +7,10 @@
7
7
  export let color = "@primary"
8
8
 
9
9
  $: wind = {
10
+ ...$$restProps,
10
11
  "@size": size,
11
12
  "$color": color,
12
13
  }
13
14
  </script>
14
15
 
15
- <ws-hexagon-spinner use:wsx={wind} />
16
+ <ws-hexagon-spinner use:wsx={wind} style="aspect-ratio: 1 / 1;" />
package/src/text.svelte CHANGED
@@ -5,14 +5,12 @@
5
5
 
6
6
  export let title = false
7
7
  export let subtitle = false
8
- export let block = false
9
8
  export let adorn = false
10
9
 
11
10
  $: wind = {
12
- "$title": title,
13
- "$subtitle": subtitle,
11
+ "$title-text": title,
12
+ "$subtitle-text": subtitle,
14
13
  "$adorn": adorn,
15
- block,
16
14
  ...$$restProps
17
15
  }
18
16
  </script>
package/src/wsx.mjs CHANGED
@@ -1,24 +1,25 @@
1
- import ws from "@axel669/windstorm"
2
-
3
- // ws.custom("outline", (o) => ws.prop("outline", o))
4
-
5
- export default (node, props) => {
6
- const update = (props) => {
7
- const { slot = null, ...goodProps } = props ?? {}
8
- if (goodProps === null || goodProps === undefined) {
9
- node.setAttribute("ws-x", null)
10
- return
11
- }
12
- node.setAttribute(
13
- "ws-x",
14
- ws.x(goodProps)
15
- )
16
- if (slot === null) {
17
- node.removeAttribute("slot")
18
- return
19
- }
20
- node.setAttribute("slot", slot)
21
- }
22
- update(props)
23
- return { update }
24
- }
1
+ import ws from "@axel669/windstorm"
2
+
3
+ export default (node, props) => {
4
+ const update = (props) => {
5
+ const { slot = null, ...goodProps } = props ?? {}
6
+ if (goodProps === null || goodProps === undefined) {
7
+ node.setAttribute("ws-x", null)
8
+ return
9
+ }
10
+ const formatted = Object.entries(goodProps).reduce(
11
+ (props, [key, value]) => {
12
+ const realKey = key.replaceAll("--", ":").replace(/^\-/, "$")
13
+ props[realKey] = value
14
+ return props
15
+ },
16
+ {}
17
+ )
18
+ node.setAttribute(
19
+ "ws-x",
20
+ ws.x(formatted)
21
+ )
22
+ }
23
+ update(props)
24
+ return { update }
25
+ }
@@ -1,27 +0,0 @@
1
- # AsyncButton
2
- A button that makes it simpler to fire off async functions in response to button
3
- clicks. In addition to calling the function, the button will disable itself
4
- during the function duration and show a load spinner inside the button.
5
-
6
- ## Props
7
- The AsyncButton supports all of the [Button](../control/button.md) props.
8
-
9
- ### handler
10
- The async function to call when the button is clicked.
11
-
12
- ## Example
13
-
14
- ```svelte
15
- <script>
16
- import { AsyncButton } from "@axel669/zephyr"
17
-
18
- const load = async () => {
19
- const res = await fetch(someURL)
20
- console.log(await res.text())
21
- }
22
- </script>
23
-
24
- <AsyncButton handler={load} color="@primary">
25
- Load Things
26
- </AsyncButton>
27
- ```
@@ -1,42 +0,0 @@
1
- # LoadZone
2
- A component for putting content that is behind an async function.
3
-
4
- ## Props
5
-
6
- ### message
7
- The text to show while the promise is pending.
8
-
9
- ### source
10
- `Promise`
11
-
12
- The promise that will resolve into some kind of content-related information.
13
-
14
- ## Slots
15
-
16
- ### default
17
- The default slot will be shown when the promise resolves.
18
-
19
- ### loading
20
- The content to show while the promise is pending. Overrides the default of a
21
- load spinner with some text.
22
-
23
- ### error
24
- The content to show when the promise rejects. Use `let:error` to get the error
25
- that was thrown.
26
-
27
- ## Example
28
-
29
- ```svelte
30
- <LoadZone source={asyncThing} let:result>
31
- <div>
32
- content
33
- </div>
34
- <div>
35
- {JSON.stringify(result)}
36
- </div>
37
-
38
- <div slot="error">
39
- :(
40
- </div>
41
- </LoadZone>
42
- ```
@@ -1,21 +0,0 @@
1
- # TH
2
-
3
- The TH component has no use outside fo the DataTable, but is used to support
4
- the filter and sorting functionality for that component.
5
-
6
- ## Props
7
-
8
- ### sort
9
- `Function`
10
-
11
- The sorting function to use for the column defined. Should return values that
12
- match the expected values for `Array.sort`.
13
-
14
- ### filter
15
- `Function`
16
-
17
- The function to use for filtering based on the column. The function is given
18
- 2 arguments: a row of data and the text from the filter input field. The
19
- function should return `true` if the item should be shown. A filter function on
20
- a specific column does not need to only look at the specified column, but not
21
- doing could cause confusion for users without proper context.
@@ -1,86 +0,0 @@
1
- # DataTable
2
-
3
- The DataTable is a more advanced way to show data on screen. Underneath is
4
- a [Table](../data-display/table.md) component, but with additional functionality
5
- for pagination, sorting, and fitering.
6
-
7
- > If pagination is not needed, the DataTable may not be necessary as it will
8
- > only be shortcutting data formatting at that point.
9
-
10
- ## Props
11
-
12
- ### color
13
- Sets `$color`
14
-
15
- ### data
16
- `Array`
17
-
18
- The data to display. Each item in the array can be in either the same
19
- format as the Table, or any kind of object if column format functions
20
- are used.
21
-
22
- ### page
23
- `Number`
24
-
25
- The current page of data being viewed. Can be bound, or set to control
26
- which page is displayed
27
-
28
- ### pageSize
29
- `Number`
30
-
31
- The number of items to show on each page. Default is 10.
32
-
33
- ### rowHeight
34
- The height of each row. The component uses this to make empty rows the same
35
- height as rows with data so that the pagination doesnt randomly resize the
36
- visual area of the table.
37
-
38
- ## Slots
39
-
40
- ### header
41
- A fragment that should contain the header cells for the table header. A standard
42
- `th` can be used, but the [TH](./data-table/th.md) element from zephyr has
43
- additional configuration to handle more complex header-related actions.
44
-
45
- ### row
46
- A fragment that should use regular `td` elements to define how a row should be
47
- layed out. The fragment will need `let:row` to access each row's data for
48
- displaying it.
49
-
50
- ## Example
51
- ```svelte
52
- <script>
53
- import { DataTable, TH, sorts } from "@axel669/zephyr"
54
-
55
- let page
56
- const data = [
57
- { a: 1, b: 1 ** 2, c: 1 ** 3 },
58
- { a: 2, b: 2 ** 2, c: 2 ** 3 },
59
- { a: 3, b: 3 ** 2, c: 3 ** 3 },
60
- { a: 4, b: 4 ** 2, c: 4 ** 3 },
61
- { a: 5, b: 5 ** 2, c: 5 ** 3 },
62
- { a: 6, b: 6 ** 2, c: 6 ** 3 },
63
- { a: 7, b: 7 ** 2, c: 7 ** 3 },
64
- { a: 8, b: 8 ** 2, c: 8 ** 3 },
65
- { a: 9, b: 9 ** 2, c: 9 ** 3 },
66
- { a: 10, b: 10 ** 2, c: 10 ** 3 },
67
- { a: 11, b: 11 ** 2, c: 11 ** 3 },
68
- { a: 12, b: 12 ** 2, c: 12 ** 3 },
69
- { a: 13, b: 13 ** 2, c: 13 ** 3 },
70
- ]
71
- </script>
72
-
73
- <DataTable {cols} {data} color="warning" pageSize={3} bind:page>
74
- <svelte:fragment slot="header">
75
- <TH sort={sorts.natural}>N</TH>
76
- <th>Squared</th>
77
- <th>Cubed</th>
78
- </svelte:fragment>
79
-
80
- <svelte:fragment slot="row" let:row>
81
- <td>{row.a}</td>
82
- <td>{row.b}</td>
83
- <td>^3 = {row.c}</td>
84
- </svelte:fragment>
85
- </DataTable>
86
- ```
@@ -1,44 +0,0 @@
1
- # EntryButton
2
-
3
- The EntryButton is a convenient way to display modals and screens over
4
- content without needing to bind variables have lots of Modal elements in
5
- addition to the buttons that show them.
6
-
7
- ## Props
8
-
9
- ### component
10
- The component to show when clicked
11
-
12
- ### props
13
- The props to pass to the component when it is shown, or a function that
14
- generates the props when called.
15
-
16
- ### this
17
- The wrapper for the component. Default is [Modal](../layout/modal.md) but any
18
- component that has the same interface as Modal will work.
19
-
20
- ## Events
21
-
22
- ### entry
23
- When the component is closed the entry event is fired. The detail
24
- property of the event will have the value from closing it.
25
-
26
- ## Example
27
- ```svelte
28
- <script>
29
- const propsFunc = () => ({
30
- now: Date.now(),
31
- rand: Math.random(),
32
- })
33
- </script>
34
-
35
- <EntryButton component={Subscreen} on:entry={console.log}>
36
- Open Subscreen
37
- </EntryButton>
38
- <EntryButton component={CoolDialog} props={{ thing: true }} on:entry={console.log}>
39
- Open Subscreen
40
- </EntryButton>
41
- <EntryButton this={CoolModal} component={CustomThing} on:entry={console.log} props={propsFunc}>
42
- Open Subscreen
43
- </EntryButton>
44
- ```
@@ -1,45 +0,0 @@
1
- # Toast
2
- Displays toast notifications along the edge of the screen. Unlike the Toaster
3
- component, this has functions for interacting with and generating toast
4
- messages, where the Toaster component has the programmer manage the content.
5
-
6
- ## Props
7
- See the Toaster component. The Toast component is wrapper around it that
8
- also controls the children being shown for convenience.
9
-
10
- ### component
11
- The component to use as a wrapper for the messages. Defaults to the
12
- ToastMessage component.
13
-
14
- ### position
15
- The position to show modals in. Uses the same positions as the Windstorm
16
- toaster.
17
-
18
- ## Functions
19
-
20
- ### show(duration, props)
21
- Shows a toast notification that will disappear after the specified
22
- duration (time in milliseconds). The props provided are passed to an
23
- instance of the component specified in the props.
24
-
25
- ## Events
26
-
27
- ### action
28
- Fired when a toast message is clicked. The info argument contains a
29
- value property that is provided by the message component, and a copy
30
- of the props passed to that instace.
31
-
32
- For the default messages, the value will be `null` if no button was
33
- clicked, and `true` if the action button was clicked. This allows
34
- actions to be taken against interactions in the message without having
35
- to bind all kinds of events or callbacks.
36
-
37
- ## Example
38
- ```svelte
39
- <script>
40
- let toast = null
41
- const notify = () => toast.show(5000, { message: "hi" })
42
- </script>
43
-
44
- <Toast bind:this={toast} position="bc" />
45
- ```
@@ -1,41 +0,0 @@
1
- # Button
2
-
3
- Basic clickable component for handling user interaction.
4
-
5
- ## Props
6
-
7
- ### color
8
- `string`
9
-
10
- Sets `$color`
11
-
12
- ### compact
13
- `bool`
14
-
15
- Sets `$compact`
16
-
17
- ### fill / outline
18
- `bool`
19
-
20
- Sets the button type to `$fill` if fill is true, `$outline` if outline
21
- is true, or `$flat` if neither is true.
22
-
23
- ## Events
24
- - click
25
-
26
- ## Example
27
- ```svelte
28
- <script>
29
- import { Button } from "@axel669/zephyr"
30
- </script>
31
-
32
- <Button on:click={action}>
33
- Flat Button
34
- </Button>
35
- <Button on:click={action} outline>
36
- Outlined Button
37
- </Button>
38
- <Button on:click={action} fill color="danger">
39
- Filled Button
40
- </Button>
41
- ```
@@ -1,87 +0,0 @@
1
- # Input
2
- A component that wraps the text-based input tags. Includes optional outline,
3
- label, hint text, error showing, input validation, input transformation, and
4
- browser level autocomplete.
5
-
6
- ## Props
7
-
8
- ### autoCompleteOptions
9
- An array of options to show for auto complete. Uses the browser `datalist`
10
- element to create the auto complete.
11
-
12
- ### color
13
- Sets the $color macro.
14
-
15
- ### disabled
16
- Disables the input.
17
-
18
- ### error
19
- If set, shows an error message under the input.
20
-
21
- ### flat
22
- If true, the input will not have a border. Default is false (with a border).
23
-
24
- ### hint
25
- Shows a hint under the label of the input.
26
-
27
- ### type
28
- The type of input. Default to "text".
29
-
30
- ### value
31
- The value of the input. Can be bound the same way a normal text input value is
32
- bound in Svelte.
33
-
34
- ### transform
35
- A function to transform the value of the input automatically. Results are put
36
- into the tvalue prop.
37
-
38
- ### tvalue
39
- The transformed value of the input. Binding should only be used to react to
40
- the value as it will be overriden while a user is typing into the input.
41
-
42
- ### validate
43
- A function to determine if the value of the input is valid. Results are put into
44
- the `valid` prop. If a transform function is provided, the transformed value
45
- is given to the validation function.
46
-
47
- ### valid
48
- The result of the validation function. Binding should only be used to react to
49
- the value.
50
-
51
- ## Instance Functions
52
-
53
- ### focus
54
- Focuses the input.
55
-
56
- ## Slots
57
-
58
- ### end
59
- Puts an element at the end of the input.
60
-
61
- ### start
62
- Puts an element at the start of the input.
63
-
64
- ## Example
65
-
66
- ```svelte
67
- <script>
68
- import { Input } from "@axel669/zephyr"
69
-
70
- let name = ""
71
- let ageText = ""
72
- let age = 0
73
- let ageValid = false
74
-
75
- $: ageError = ageValid ? "Invalid Age" : null
76
- </script>
77
-
78
- <Input bind:value={name} label="Name" />
79
- <Input
80
- bind:value={ageText}
81
- transform={v => parseInt(v)}
82
- bind:tvalue={age}
83
- validate={age => age > 0}
84
- bind:valid={ageValid}
85
- error={ageError}
86
- />
87
- ```
@@ -1,48 +0,0 @@
1
- # Label
2
- The label component is a wrapper around a `<label>` element.
3
-
4
- ## Props
5
-
6
- ### button
7
- `bool`
8
-
9
- If true, the label will have the button appearance.
10
-
11
- ### color
12
- `string`
13
-
14
- Sets `$color`
15
-
16
- ### compact
17
- `bool`
18
-
19
- If true, will make the label button be more compact. No effect is `button` is
20
- `false`.
21
-
22
- ### disabled
23
- `bool`
24
-
25
- Disables the label.
26
-
27
- ### fill / outline / flat
28
- `bool`
29
-
30
- Sets the button variant of the label when `button` is `true`.
31
-
32
- ### for
33
- `string`
34
-
35
- [Label for attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label#for)
36
-
37
- ## Example
38
-
39
- ```svelte
40
- <script>
41
- import { Label } from "@axel669/zephyr"
42
- </script>
43
-
44
- <Label for="checkbox">Toggle Checkbox</Label>
45
- <Label for="checkbox" button color="primary" fill>
46
- Open Menu
47
- </Label>
48
- ```