@rokkit/ui 1.0.0-next.106 → 1.0.0-next.107

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 (55) hide show
  1. package/dist/index.d.ts +12 -0
  2. package/dist/input/types.d.ts +9 -0
  3. package/dist/lib/fields.d.ts +16 -0
  4. package/dist/lib/form.d.ts +95 -0
  5. package/dist/lib/index.d.ts +5 -0
  6. package/dist/lib/layout.d.ts +7 -0
  7. package/dist/lib/nested.d.ts +48 -0
  8. package/dist/lib/schema.d.ts +7 -0
  9. package/dist/lib/select.d.ts +8 -0
  10. package/dist/wrappers/index.d.ts +3 -0
  11. package/package.json +1 -1
  12. package/src/Accordion.svelte +49 -25
  13. package/src/BreadCrumbs.svelte +9 -5
  14. package/src/Carousel.svelte +49 -0
  15. package/src/DataEditor.svelte +31 -0
  16. package/src/DropDown.svelte +68 -0
  17. package/src/DropSearch.svelte +37 -0
  18. package/src/FieldLayout.svelte +48 -0
  19. package/src/Fillable.svelte +19 -0
  20. package/src/Form.svelte +17 -0
  21. package/src/Item.svelte +12 -11
  22. package/src/List.svelte +55 -31
  23. package/src/ListEditor.svelte +44 -0
  24. package/src/MultiSelect.svelte +48 -0
  25. package/src/NestedEditor.svelte +88 -0
  26. package/src/NestedList.svelte +8 -42
  27. package/src/NestedPaginator.svelte +59 -0
  28. package/src/Node.svelte +21 -24
  29. package/src/PageNavigator.svelte +94 -0
  30. package/src/ProgressDots.svelte +53 -0
  31. package/src/Select.svelte +108 -0
  32. package/src/Slider.svelte +14 -0
  33. package/src/Stage.svelte +41 -0
  34. package/src/Stepper.svelte +66 -0
  35. package/src/Summary.svelte +5 -8
  36. package/src/Tabs.svelte +17 -12
  37. package/src/Tree.svelte +28 -20
  38. package/src/TreeTable.svelte +5 -4
  39. package/src/index.js +14 -0
  40. package/src/input/Input.svelte +17 -0
  41. package/src/input/InputField.svelte +69 -0
  42. package/src/input/InputSelect.svelte +23 -0
  43. package/src/input/InputSwitch.svelte +19 -0
  44. package/src/input/types.js +29 -0
  45. package/src/lib/fields.js +118 -0
  46. package/src/lib/form.js +72 -0
  47. package/src/lib/index.js +12 -0
  48. package/src/lib/layout.js +63 -0
  49. package/src/lib/nested.js +192 -0
  50. package/src/lib/schema.js +32 -0
  51. package/src/lib/select.js +38 -0
  52. package/src/wrappers/Category.svelte +26 -0
  53. package/src/wrappers/Section.svelte +16 -0
  54. package/src/wrappers/Wrapper.svelte +12 -0
  55. package/src/wrappers/index.js +3 -0
package/dist/index.d.ts CHANGED
@@ -24,7 +24,19 @@ export { default as List } from "./List.svelte";
24
24
  export { default as Accordion } from "./Accordion.svelte";
25
25
  export { default as NestedList } from "./NestedList.svelte";
26
26
  export { default as Tree } from "./Tree.svelte";
27
+ export { default as Tabs } from "./Tabs.svelte";
28
+ export { default as Select } from "./Select.svelte";
29
+ export { default as MultiSelect } from "./MultiSelect.svelte";
30
+ export { default as DropDown } from "./DropDown.svelte";
31
+ export { default as Table } from "./TreeTable.svelte";
27
32
  export { default as ToggleThemeMode } from "./ToggleThemeMode.svelte";
28
33
  export { default as Overlay } from "./Overlay.svelte";
29
34
  export { default as Message } from "./Message.svelte";
30
35
  export { default as SlidingColumns } from "./SlidingColumns.svelte";
36
+ export { default as InputField } from "./input/InputField.svelte";
37
+ export { default as Form } from "./Form.svelte";
38
+ export { default as FieldLayout } from "./FieldLayout.svelte";
39
+ export { default as DataEditor } from "./DataEditor.svelte";
40
+ export { default as NestedEditor } from "./NestedEditor.svelte";
41
+ export { default as Stepper } from "./Stepper.svelte";
42
+ export { default as ProgressDots } from "./ProgressDots.svelte";
@@ -0,0 +1,9 @@
1
+ export namespace types {
2
+ export let string: any;
3
+ export let integer: any;
4
+ export { CheckBox as boolean };
5
+ export { InputSelect as enum };
6
+ export let phone: any;
7
+ }
8
+ import CheckBox from '../CheckBox.svelte';
9
+ import InputSelect from './InputSelect.svelte';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Find an attribute in a schema by path
3
+ * @param {string} scope
4
+ * @param {import('../types').DataSchema} schema
5
+ * @returns {import('../types').LayoutSchema}
6
+ * @throws {Error} Invalid path
7
+ */
8
+ export function findAttributeByPath(scope: string, schema: import("../types").DataSchema): import("../types").LayoutSchema;
9
+ /**
10
+ * Get combined schema and layout
11
+ * @param {*} data
12
+ * @param {import('../types').DataSchema} schema
13
+ * @param {import('../types').LayoutSchema} layout
14
+ * @returns {import('../types').LayoutSchema}
15
+ */
16
+ export function getSchemaWithLayout(schema: import("../types").DataSchema, layout: import("../types").LayoutSchema): import("../types").LayoutSchema;
@@ -0,0 +1,95 @@
1
+ export namespace messages {
2
+ let required: string;
3
+ let email: string;
4
+ let url: string;
5
+ let color: string;
6
+ let number: string;
7
+ let min: string;
8
+ let max: string;
9
+ let pattern: string;
10
+ let exclusiveMin: string;
11
+ let exclusiveMax: string;
12
+ let minLength: string;
13
+ let maxLength: string;
14
+ let minItems: string;
15
+ let maxItems: string;
16
+ let uniqueItems: string;
17
+ let contains: string;
18
+ let exclude: string;
19
+ let integer: string;
20
+ }
21
+ export namespace dataTypes {
22
+ export namespace integer_1 {
23
+ let editor: string;
24
+ namespace props {
25
+ let type: string;
26
+ let step: number;
27
+ }
28
+ let availableProps: string[];
29
+ }
30
+ export { integer_1 as integer };
31
+ export namespace number_1 {
32
+ let editor_1: string;
33
+ export { editor_1 as editor };
34
+ export namespace props_1 {
35
+ let type_1: string;
36
+ export { type_1 as type };
37
+ let step_1: number;
38
+ export { step_1 as step };
39
+ }
40
+ export { props_1 as props };
41
+ let availableProps_1: string[];
42
+ export { availableProps_1 as availableProps };
43
+ }
44
+ export { number_1 as number };
45
+ export namespace range {
46
+ let editor_2: string;
47
+ export { editor_2 as editor };
48
+ export namespace props_2 {
49
+ let type_2: string;
50
+ export { type_2 as type };
51
+ }
52
+ export { props_2 as props };
53
+ }
54
+ export let string: {
55
+ default: string;
56
+ text: string;
57
+ password: string;
58
+ email: string;
59
+ url: string;
60
+ tel: string;
61
+ date: string;
62
+ 'datetime-local': string;
63
+ time: string;
64
+ week: string;
65
+ month: string;
66
+ file: string;
67
+ hidden: string;
68
+ color: string;
69
+ colorpicker: string;
70
+ };
71
+ export namespace _enum {
72
+ let _default: string;
73
+ export { _default as default };
74
+ export let select: string;
75
+ export let radio: string;
76
+ }
77
+ export { _enum as enum };
78
+ export namespace boolean {
79
+ let _default_1: string;
80
+ export { _default_1 as default };
81
+ export let checkbox: string;
82
+ let _switch: string;
83
+ export { _switch as switch };
84
+ let radio_1: string;
85
+ export { radio_1 as radio };
86
+ }
87
+ export namespace array {
88
+ let _default_2: string;
89
+ export { _default_2 as default };
90
+ }
91
+ export namespace object {
92
+ let _default_3: string;
93
+ export { _default_3 as default };
94
+ }
95
+ }
@@ -1 +1,6 @@
1
1
  export { addRootNode } from "./tree";
2
+ export { deriveSchemaFromValue } from "./schema";
3
+ export { deriveLayoutFromValue } from "./layout";
4
+ export { messages, dataTypes } from "./form";
5
+ export { getSchemaWithLayout, findAttributeByPath } from "./fields";
6
+ export { deriveNestedSchema, flattenAttributes, flattenObject, flattenElement, generateIndex, generateTreeTable } from "./nested";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Derives a layout from a given value.
3
+ * @param {any} value
4
+ * @param {string} scope
5
+ * @returns {import('../types').DataLayout}
6
+ */
7
+ export function deriveLayoutFromValue(value: any, scope?: string): import("../types").DataLayout;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Flattens an object into a flat object
3
+ *
4
+ * @param {Object} input - The object to flatten
5
+ * @param {String} scope - The scope of the object
6
+ */
7
+ export function flattenObject(input: Object, scope?: string): any;
8
+ /**
9
+ * Flattens an object into an array of key-value pairs
10
+ *
11
+ * @param {Object} input - The object to flatten
12
+ * @param {String} scope - The scope of the object
13
+ */
14
+ export function flattenAttributes(input: Object, scope?: string): {
15
+ key: string;
16
+ value: any;
17
+ type: string;
18
+ scope: string;
19
+ }[];
20
+ /**
21
+ * Derives a nested schema from an object
22
+ *
23
+ * @param {Object} input - The object to derive the schema from
24
+ * @param {String} scope - The scope of the object
25
+ * @returns {Object} The derived schema
26
+ */
27
+ export function deriveNestedSchema(input: Object, scope?: string): Object;
28
+ /**
29
+ * Flattens an element into a flat object
30
+ *
31
+ * @param {Object} element - The element to flatten
32
+ */
33
+ export function flattenElement(element: Object): any;
34
+ /**
35
+ * Generates an index array referencing the input data
36
+ *
37
+ * @param {Object} data - The flat object to index
38
+ * @param {String} key - The key to use as index
39
+ */
40
+ export function generateIndex(data: Object, key?: string): any;
41
+ /**
42
+ * Generates a tree table from the input data
43
+ *
44
+ * @param {Object} data - The data to generate the tree table from
45
+ * @param {String} key - The key to use as index
46
+ * @param {Boolean} ellipsis - Whether to truncate the value
47
+ */
48
+ export function generateTreeTable(data: Object, key?: string, ellipsis?: boolean): any;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Derives a schema from a given value.
3
+ *
4
+ * @param {any} data
5
+ * @returns {import('../types').DataSchema}
6
+ */
7
+ export function deriveSchemaFromValue(data: any): import("../types").DataSchema;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Get the optimal position for the list based on anchor and viewport dimensions.
3
+ *
4
+ * @param {HTMLElement} anchor - The anchor element to position the list relative to.
5
+ * @param {HTMLElement} viewport - The viewport element that determines the position.
6
+ * @returns {string} - A string with CSS position properties and values.
7
+ */
8
+ export function getListPosition(anchor: HTMLElement, viewport: HTMLElement): string;
@@ -0,0 +1,3 @@
1
+ export { default as Wrapper } from "./Wrapper.svelte";
2
+ export { default as Section } from "./Section.svelte";
3
+ export { default as Category } from "./Category.svelte";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rokkit/ui",
3
- "version": "1.0.0-next.106",
3
+ "version": "1.0.0-next.107",
4
4
  "description": "Organisms are larger, more complex building blocks that are composed of multiple molecules",
5
5
  "author": "Jerry Thomas <me@jerrythomas.name>",
6
6
  "license": "MIT",
@@ -1,10 +1,10 @@
1
1
  <script>
2
2
  import { equals } from 'ramda'
3
- import { createEmitter, noop, getKeyFromPath } from '@rokkit/core'
4
- import { DataWrapper } from '@rokkit/states'
3
+ import { createEmitter, noop, getKeyFromPath, getSnippet } from '@rokkit/core'
4
+ import { NestedProxy } from '@rokkit/states'
5
5
  import { navigator } from '@rokkit/actions'
6
- import { defaultMapping } from './constants'
7
6
  import Summary from './Summary.svelte'
7
+ import Item from './Item.svelte'
8
8
 
9
9
  /**
10
10
  * @typedef {Object} Props
@@ -20,32 +20,40 @@
20
20
  let {
21
21
  class: classes = '',
22
22
  items = $bindable([]),
23
- mapping = defaultMapping,
23
+ value = $bindable(null),
24
+ fields,
24
25
  autoCloseSiblings = false,
25
26
  multiselect = false,
26
- value = $bindable(null),
27
+ header = null,
28
+ footer = null,
29
+ empty = null,
30
+ stub = null,
31
+ extra,
27
32
  ...events
28
33
  } = $props()
29
34
 
30
35
  let emitter = $derived(
31
36
  createEmitter(events, ['collapse', 'change', 'expand', 'click', 'select', 'move'])
32
37
  )
33
- let wrapper = new DataWrapper(items, mapping, value, { events, multiselect, autoCloseSiblings })
38
+ let wrapper = new NestedProxy(items, value, fields, { events, multiselect, autoCloseSiblings })
34
39
  </script>
35
40
 
36
- {#snippet listItems(items, wrapper, hierarchy = [], onchange = noop)}
37
- {@const mapping = wrapper.mapping}
38
- {#each items as item, index}
39
- {@const Template = mapping.getComponent(item)}
40
- {@const path = getKeyFromPath([...hierarchy, index])}
41
- {@const props = mapping.getAttribute(item, 'props') || {}}
41
+ {#snippet listItems(nodes, onchange = noop)}
42
+ {#each nodes as node}
43
+ {@const template = getSnippet(extra, node.get('component')) ?? stub}
44
+ {@const path = getKeyFromPath(node.path)}
45
+ {@const props = node.get('props') || {}}
42
46
  <rk-list-item
43
47
  role="option"
44
48
  data-path={path}
45
- aria-selected={wrapper.selected.has(path)}
46
- aria-current={equals(wrapper.currentNode, item)}
49
+ aria-selected={node.selected}
50
+ aria-current={node.focused}
47
51
  >
48
- <Template bind:value={items[index]} {mapping} onchange={events.change} {...props} />
52
+ {#if template}
53
+ {@render template(node, props, onchange)}
54
+ {:else}
55
+ <Item value={node.value} fields={node.fields} />
56
+ {/if}
49
57
  </rk-list-item>
50
58
  {/each}
51
59
  {/snippet}
@@ -56,23 +64,39 @@
56
64
  use:navigator={{ wrapper }}
57
65
  onactivate={() => (value = wrapper.value)}
58
66
  >
59
- {#each wrapper.data as item, index}
60
- {@const hasItems = mapping.hasChildren(item)}
61
- {@const id = 'id-' + index}
62
-
67
+ {#if header}
68
+ <rk-header>{@render header()}</rk-header>
69
+ {/if}
70
+ {#if wrapper.nodes.length === 0}
71
+ <rk-list-item role="presentation">
72
+ {#if empty}
73
+ {@render empty()}
74
+ {:else}
75
+ No items found.
76
+ {/if}
77
+ </rk-list-item>
78
+ {/if}
79
+ {#each wrapper.nodes as node, index}
63
80
  <div
64
- {id}
65
81
  class="flex flex-col"
66
- class:is-expanded={mapping.isExpanded(item)}
67
- class:is-selected={equals(item, value)}
82
+ class:is-expanded={node.expanded}
83
+ class:is-selected={node.selected}
68
84
  data-path={index}
69
85
  >
70
- <Summary {mapping} bind:value={items[index]} expanded={mapping.isExpanded(item)} />
71
- {#if hasItems && mapping.isExpanded(item)}
86
+ <Summary
87
+ bind:value={wrapper.nodes[index].value}
88
+ fields={node.fields}
89
+ expanded={node.expanded}
90
+ hasChildren={node.hasChildren()}
91
+ />
92
+ {#if node.expanded}
72
93
  <rk-list role="listbox" tabindex="-1">
73
- {@render listItems(item[mapping.fields.children], wrapper, [index], events.change)}
94
+ {@render listItems(node.children, events.change)}
74
95
  </rk-list>
75
96
  {/if}
76
97
  </div>
77
98
  {/each}
99
+ {#if footer}
100
+ <rk-footer>{@render footer()}</rk-footer>
101
+ {/if}
78
102
  </rk-accordion>
@@ -1,5 +1,6 @@
1
1
  <script>
2
- import { defaultMapping } from './constants'
2
+ import { getSnippet } from '@rokkit/core'
3
+ import Item from './Item.svelte'
3
4
 
4
5
  /**
5
6
  * @typedef {Object} Props
@@ -7,16 +8,15 @@
7
8
  * @property {any} [items]
8
9
  * @property {string} [separator]
9
10
  * @property {any} [fields]
10
- * @property {any} [using]
11
+ * @property {any} [crumb]
11
12
  */
12
13
 
13
14
  /** @type {Props} */
14
- let { class: classes = '', items = [], separator = '/', mapping = defaultMapping } = $props()
15
+ let { class: classes = '', items = [], separator = '/', fields, crumb } = $props()
15
16
  </script>
16
17
 
17
18
  <rk-crumbs class={classes}>
18
19
  {#each items as item, index}
19
- {@const Component = mapping.getComponent(item)}
20
20
  {#if index > 0}
21
21
  <span>
22
22
  {#if separator.length === 1}
@@ -27,7 +27,11 @@
27
27
  </span>
28
28
  {/if}
29
29
  <rk-crumb class:is-selected={index === items.length - 1}>
30
- <Component value={item} {mapping} />
30
+ {#if crumb}
31
+ {@render crumb(item, fields)}
32
+ {:else}
33
+ <Item value={item} {fields} />
34
+ {/if}
31
35
  </rk-crumb>
32
36
  {/each}
33
37
  </rk-crumbs>
@@ -0,0 +1,49 @@
1
+ <script>
2
+ let className = ''
3
+ export { className as class }
4
+ export let items = []
5
+ export let value
6
+ let currentIndex = 0
7
+
8
+ function handleKey(e, index) {
9
+ const prevIndex = currentIndex
10
+ if (['Enter', ' '].includes(e.key)) {
11
+ currentIndex = index
12
+ } else {
13
+ if (e.key === 'ArrowRight') {
14
+ currentIndex = currentIndex === items.length - 1 ? 0 : currentIndex + 1
15
+ } else if (e.key === 'ArrowLeft') {
16
+ currentIndex = currentIndex === 0 ? items.length - 1 : currentIndex - 1
17
+ }
18
+ }
19
+ if (currentIndex !== prevIndex) {
20
+ e.preventDefault()
21
+ e.stopPropagation()
22
+ }
23
+ }
24
+ $: value = items[currentIndex]
25
+ </script>
26
+
27
+ {#if items.length === 0}
28
+ <p>No items to display</p>
29
+ {:else}
30
+ <carousel class="flex w-full flex-col gap-3 {className}">
31
+ <slide class="flex flex-col">
32
+ <img src={value.src} alt={value.alt} />
33
+ <p>{value.text}</p>
34
+ </slide>
35
+ <dot-nav role="radiogroup">
36
+ {#each items as item, index}
37
+ <dot
38
+ role="radio"
39
+ aria-checked={currentIndex === index}
40
+ aria-label={`Slide ${index + 1}`}
41
+ on:click={() => (currentIndex = index)}
42
+ on:keydown={(e) => handleKey(e, index)}
43
+ tabindex={0}
44
+ >
45
+ </dot>
46
+ {/each}
47
+ </dot-nav>
48
+ </carousel>
49
+ {/if}
@@ -0,0 +1,31 @@
1
+ <script>
2
+ import { setContext } from 'svelte'
3
+ import { writable } from 'svelte/store'
4
+ import { types } from './input/types'
5
+ import Wrapper from './wrappers/Wrapper.svelte'
6
+ import Item from './Item.svelte'
7
+ import Tabs from './Tabs.svelte'
8
+ import FieldLayout from './FieldLayout.svelte'
9
+ import { noop } from '@rokkit/core'
10
+
11
+ const registry = $state({})
12
+ setContext('registry', registry)
13
+
14
+ import { deriveSchemaFromValue, deriveLayoutFromValue, getSchemaWithLayout } from './lib'
15
+
16
+ let { value, schema = null, layout = null, using = {}, onchange = noop } = $props()
17
+
18
+ registry.editors = { ...types, ...using?.editors }
19
+ registry.components = { default: Item, ...using?.components }
20
+ registry.wrappers = { default: Wrapper, ...using?.wrappers }
21
+ registry.navigators = { default: Tabs, ...using?.navigators }
22
+
23
+ let schemaWithLayout = $derived.by(() => {
24
+ return getSchemaWithLayout(
25
+ schema ?? deriveSchemaFromValue(value),
26
+ layout ?? deriveLayoutFromValue(value)
27
+ )
28
+ })
29
+ </script>
30
+
31
+ <FieldLayout schema={schemaWithLayout} bind:value {onchange} />
@@ -0,0 +1,68 @@
1
+ <script>
2
+ import { defaultFields, defaultStateIcons } from '@rokkit/core'
3
+ import { dismissable } from '@rokkit/actions'
4
+ import Icon from './Icon.svelte'
5
+ import Slider from './Slider.svelte'
6
+ import Item from './Item.svelte'
7
+ import List from './List.svelte'
8
+
9
+ let {
10
+ class: className,
11
+ options = [],
12
+ fields = defaultFields,
13
+ using = { default: Item },
14
+ value = null,
15
+ title = null,
16
+ icon = null,
17
+ small = false,
18
+ disabled = false
19
+ } = $props()
20
+
21
+ using = { default: Item, ...using }
22
+ fields = { ...defaultFields, ...fields }
23
+
24
+ let offsetTop = $state(0)
25
+ let open = $state(false)
26
+ let icons = defaultStateIcons.selector
27
+
28
+ function handleSelect(event) {
29
+ open = false
30
+ // dispatch('change', event.detail)
31
+ }
32
+ </script>
33
+
34
+ <drop-down
35
+ class="dropdown relative flex cursor-pointer select-none {className}"
36
+ class:open
37
+ aria-haspopup="true"
38
+ aria-controls="menu"
39
+ >
40
+ <button
41
+ class="flex items-center"
42
+ bind:clientHeight={offsetTop}
43
+ tabindex="0"
44
+ use:dismissable
45
+ ondismiss={() => (open = false)}
46
+ onfocus={() => (open = true)}
47
+ onblur={() => (open = false)}
48
+ >
49
+ <span class="flex items-center">
50
+ {#if icon !== null}
51
+ <Icon name={icon} />
52
+ {/if}
53
+ {#if !small && title}
54
+ <p class="flex w-full">{title}</p>
55
+ {/if}
56
+ {#if open}
57
+ <Icon name={icons.opened} />
58
+ {:else}
59
+ <Icon name={icons.closed} />
60
+ {/if}
61
+ </span>
62
+ </button>
63
+ {#if open}
64
+ <Slider top={offsetTop + 4}>
65
+ <List items={options} {fields} {using} bind:value onselect={handleSelect} tabindex="-1" />
66
+ </Slider>
67
+ {/if}
68
+ </drop-down>
@@ -0,0 +1,37 @@
1
+ <script>
2
+ import { defaultFields, getText } from '@rokkit/core'
3
+ import Select from './Select.svelte'
4
+
5
+ let { options, name, value, fields = defaultFields, ...restProps } = $props()
6
+
7
+ let searchText = $state('')
8
+ let searchBox
9
+ let filtered = $state(options)
10
+
11
+ fields = { ...defaultFields, ...fields }
12
+
13
+ function applySearch(event) {
14
+ searchText = event.target.value
15
+ if (searchText) {
16
+ filtered = options.filter((option) =>
17
+ getText(option, fields).toLowerCase().includes(searchText.toLowerCase())
18
+ )
19
+ } else filtered = options
20
+ }
21
+ function handleSelect(event) {
22
+ value = event.detail
23
+ searchText = getText(event.detail, fields)
24
+ }
25
+ </script>
26
+
27
+ <Select {name} bind:value options={filtered} {...restProps} {fields} onselect={handleSelect}>
28
+ <span class="flex flex-grow">
29
+ <input
30
+ type="text"
31
+ class="w-full border-none bg-transparent p-0"
32
+ bind:value={searchText}
33
+ bind:this={searchBox}
34
+ onchange={applySearch}
35
+ />
36
+ </span>
37
+ </Select>
@@ -0,0 +1,48 @@
1
+ <script>
2
+ import { getContext } from 'svelte'
3
+ import { omit } from 'ramda'
4
+ import InputField from './input/InputField.svelte'
5
+ import FieldLayout from './FieldLayout.svelte'
6
+
7
+ // const dispatch = createEventDispatcher()
8
+ const registry = getContext('registry')
9
+
10
+ export let value = {}
11
+ export let schema = {}
12
+ export let path = []
13
+
14
+ function handle() {
15
+ dispatch('change', value)
16
+ }
17
+
18
+ let Wrapper = registry.wrappers[schema.wrapper] ?? registry.wrappers.default
19
+ let wrapperProps = omit(['wrapper', 'elements', 'key'], schema)
20
+ </script>
21
+
22
+ {#if !Array.isArray(schema.elements)}
23
+ <error> Invalid schema. Expected schema to include an 'elements' array. </error>
24
+ {:else}
25
+ <Wrapper {...wrapperProps}>
26
+ {#each schema.elements as item}
27
+ {@const elementPath = item.key ? [...path, item.key] : path}
28
+ {@const props = { ...item.props, path: elementPath }}
29
+ {@const nested = Array.isArray(item.elements) && item.elements.length > 0}
30
+ {@const Component = item.component
31
+ ? (registry.components[item.component] ?? registry.components.default)
32
+ : null}
33
+
34
+ {#if nested}
35
+ {#if item.key}
36
+ <FieldLayout {...props} schema={item} bind:value={value[item.key]} on:change={handle} />
37
+ {:else}
38
+ <FieldLayout {...props} schema={item} bind:value on:change={handle} />
39
+ {/if}
40
+ {:else if Component}
41
+ <Component {...item.props} value={item.key ? value[item.key] : null} />
42
+ {:else}
43
+ {@const name = elementPath.join('.')}
44
+ <InputField {name} bind:value={value[item.key]} {...item.props} on:change={handle} />
45
+ {/if}
46
+ {/each}
47
+ </Wrapper>
48
+ {/if}
@@ -0,0 +1,19 @@
1
+ <script>
2
+ import { marked } from 'marked'
3
+ import { mangle } from 'marked-mangle'
4
+ import { gfmHeadingId } from 'marked-gfm-heading-id'
5
+ import { fillable } from '@rokkit/actions'
6
+
7
+ export let text = ''
8
+ export let options = []
9
+ export let current = 0
10
+ export let check = false
11
+
12
+ marked.use(mangle())
13
+ marked.use(gfmHeadingId())
14
+ </script>
15
+
16
+ <!-- eslint-disable svelte/no-at-html-tags -->
17
+ <div use:fillable={{ options, current, check }} on:remove class="flex-grow">
18
+ {@html marked(text)}
19
+ </div>
@@ -0,0 +1,17 @@
1
+ <script>
2
+ import DataEditor from './DataEditor.svelte'
3
+
4
+ export let value
5
+ export let schema = null
6
+ export let layout = null
7
+ export let using = {}
8
+ </script>
9
+
10
+ <form on:submit>
11
+ <DataEditor bind:value {schema} {layout} {using} />
12
+ <span>
13
+ <slot>
14
+ <button type="submit">Submit</button>
15
+ </slot>
16
+ </span>
17
+ </form>