sveltacular 0.0.40 → 0.0.42

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.
@@ -0,0 +1,74 @@
1
+ <script>import {
2
+ FlexRow,
3
+ ListBox,
4
+ RadioBox,
5
+ TextBox
6
+ } from "../../index.js";
7
+ import FlexCol from "../../layout/flex-col.svelte";
8
+ export let mode = "existing";
9
+ export let newValue = "";
10
+ export let existingValue = "";
11
+ export let items = [];
12
+ export let size = "full";
13
+ export let disabled = false;
14
+ export let required = false;
15
+ export let searchable = false;
16
+ export let search = void 0;
17
+ export let searchPlaceholder = "Search";
18
+ export let newPlaceholder = "New";
19
+ </script>
20
+
21
+ <div class="group">
22
+ <FlexRow>
23
+ <div class="labels">
24
+ <FlexCol>
25
+ <div class="radio">
26
+ <RadioBox value="existing" bind:group={mode}>Existing:</RadioBox>
27
+ </div>
28
+ <div class="radio">
29
+ <RadioBox value="new" bind:group={mode}>New:</RadioBox>
30
+ </div>
31
+ </FlexCol>
32
+ </div>
33
+ <div class="inputs">
34
+ <FlexCol>
35
+ <div class="input">
36
+ <ListBox
37
+ bind:value={existingValue}
38
+ {searchable}
39
+ {search}
40
+ {required}
41
+ {items}
42
+ {size}
43
+ placeholder={searchPlaceholder}
44
+ disabled={disabled || mode == 'new'}
45
+ />
46
+ </div>
47
+ <div class="input">
48
+ <TextBox
49
+ bind:value={newValue}
50
+ {size}
51
+ placeholder={newPlaceholder}
52
+ disabled={disabled || mode == 'existing'}
53
+ />
54
+ </div>
55
+ </FlexCol>
56
+ </div>
57
+ </FlexRow>
58
+ </div>
59
+
60
+ <style>
61
+ .labels {
62
+ flex-shrink: 1;
63
+ }
64
+ .inputs {
65
+ flex-grow: 1;
66
+ }
67
+ .radio,
68
+ .input {
69
+ height: 2.5rem;
70
+ }
71
+ .radio {
72
+ padding-top: 0.1rem;
73
+ }
74
+ </style>
@@ -0,0 +1,28 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import { type DropdownOption, type FormFieldSizeOptions } from '../../index.js';
3
+ import type { SearchFunction } from '../list-box/list-box.js';
4
+ declare const __propDef: {
5
+ props: {
6
+ mode?: "new" | "existing" | undefined;
7
+ newValue?: string | undefined;
8
+ existingValue?: string | undefined;
9
+ items?: DropdownOption[] | undefined;
10
+ size?: FormFieldSizeOptions | undefined;
11
+ disabled?: boolean | undefined;
12
+ required?: boolean | undefined;
13
+ searchable?: boolean | undefined;
14
+ search?: SearchFunction | undefined;
15
+ searchPlaceholder?: string | undefined;
16
+ newPlaceholder?: string | undefined;
17
+ };
18
+ events: {
19
+ [evt: string]: CustomEvent<any>;
20
+ };
21
+ slots: {};
22
+ };
23
+ export type NewOrExistingComboProps = typeof __propDef.props;
24
+ export type NewOrExistingComboEvents = typeof __propDef.events;
25
+ export type NewOrExistingComboSlots = typeof __propDef.slots;
26
+ export default class NewOrExistingCombo extends SvelteComponent<NewOrExistingComboProps, NewOrExistingComboEvents, NewOrExistingComboSlots> {
27
+ }
28
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { DropdownOption } from '../../index.js';
2
+ export type SearchFunction = (text: string) => Promise<DropdownOption[]>;
@@ -0,0 +1 @@
1
+ export {};
@@ -13,11 +13,12 @@ export let disabled = false;
13
13
  export let required = false;
14
14
  export let searchable = false;
15
15
  export let search = void 0;
16
+ export let placeholder = "";
16
17
  const id = uniqueId();
17
18
  const dispatch = createEventDispatcher();
18
19
  const getText = () => items.find((item) => item.value == value)?.name || "";
19
20
  let text = getText();
20
- let open = false;
21
+ let isMenuOpen = false;
21
22
  let highlightIndex = -1;
22
23
  let filteredItems = [];
23
24
  $:
@@ -27,29 +28,29 @@ const onSelect = (e) => {
27
28
  dispatch("change", value);
28
29
  text = getText();
29
30
  applyFilter();
30
- open = false;
31
+ isMenuOpen = false;
31
32
  };
32
33
  const focusOnInput = () => {
33
34
  if (browser)
34
35
  document.getElementById(id)?.focus();
35
36
  };
36
- const toggle = () => open = !open;
37
+ const toggle = () => isMenuOpen = !open;
37
38
  const clickArrow = () => {
38
39
  if (disabled)
39
40
  return;
40
41
  toggle();
41
- if (open)
42
+ if (isMenuOpen)
42
43
  focusOnInput();
43
44
  };
44
45
  const onInputKeyPress = (e) => {
45
46
  if (disabled)
46
47
  return;
47
48
  if (e.key == "Escape") {
48
- open = false;
49
+ isMenuOpen = false;
49
50
  return;
50
51
  }
51
52
  if (e.key == "Enter" || e.key == "Tab") {
52
- open = false;
53
+ isMenuOpen = false;
53
54
  if (highlightIndex > -1) {
54
55
  onSelect(new CustomEvent("select", { detail: filteredItems[highlightIndex] }));
55
56
  }
@@ -57,17 +58,17 @@ const onInputKeyPress = (e) => {
57
58
  }
58
59
  if (e.key == "ArrowDown") {
59
60
  highlightIndex = Math.min(highlightIndex + 1, filteredItems.length - 1);
60
- open = true;
61
+ isMenuOpen = true;
61
62
  return;
62
63
  }
63
64
  if (e.key == "ArrowUp") {
64
65
  highlightIndex = Math.max(highlightIndex - 1, -1);
65
66
  if (highlightIndex == -1)
66
- open = false;
67
+ isMenuOpen = false;
67
68
  return;
68
69
  }
69
70
  if (e.key.length == 1 || e.key == "Backspace" || e.key == "Delete") {
70
- open = true;
71
+ isMenuOpen = true;
71
72
  highlightIndex = 0;
72
73
  triggerSearch();
73
74
  }
@@ -99,6 +100,8 @@ const updateText = async () => {
99
100
  }
100
101
  };
101
102
  triggerSearch();
103
+ $:
104
+ open = isMenuOpen && !disabled;
102
105
  </script>
103
106
 
104
107
  <FormField {size}>
@@ -112,8 +115,9 @@ triggerSearch();
112
115
  bind:value={text}
113
116
  {required}
114
117
  {disabled}
118
+ {placeholder}
115
119
  readonly={!isSeachable}
116
- on:focus={() => (open = true)}
120
+ on:focus={() => (isMenuOpen = true)}
117
121
  on:keyup={onInputKeyPress}
118
122
  data-value={value}
119
123
  data-text={text}
@@ -1,5 +1,6 @@
1
1
  import { SvelteComponent } from "svelte";
2
2
  import type { DropdownOption, FormFieldSizeOptions } from '../../types/form.js';
3
+ import type { SearchFunction } from './list-box.js';
3
4
  declare const __propDef: {
4
5
  props: {
5
6
  value?: string | undefined;
@@ -8,7 +9,8 @@ declare const __propDef: {
8
9
  disabled?: boolean | undefined;
9
10
  required?: boolean | undefined;
10
11
  searchable?: boolean | undefined;
11
- search?: ((text: string) => Promise<DropdownOption[]>) | undefined;
12
+ search?: SearchFunction | undefined;
13
+ placeholder?: string | undefined;
12
14
  };
13
15
  events: {
14
16
  change: CustomEvent<string>;
@@ -56,6 +56,7 @@ label .checkbox .checkmark {
56
56
  label input {
57
57
  width: 0;
58
58
  height: 0;
59
+ position: absolute;
59
60
  }
60
61
  label input:checked + .checkbox {
61
62
  background-color: var(--form-input-selected-bg, #3182ce);
@@ -46,7 +46,7 @@ const onInput = (e) => {
46
46
  {#if $$slots.default}
47
47
  <FormLabel {id} {required}><slot /></FormLabel>
48
48
  {/if}
49
- <div class="input">
49
+ <div class="input {disabled ? 'disabled' : 'enabled'}">
50
50
  {#if prefix}
51
51
  <div class="prefix">{prefix}</div>
52
52
  {/if}
@@ -91,6 +91,9 @@ const onInput = (e) => {
91
91
  user-select: none;
92
92
  white-space: nowrap;
93
93
  }
94
+ .input.disabled {
95
+ opacity: 0.5;
96
+ }
94
97
  .input input {
95
98
  background-color: transparent;
96
99
  border: none;
@@ -0,0 +1,38 @@
1
+ <script>export let text = "No data to display";
2
+ </script>
3
+
4
+ <div class="empty">
5
+ {#if $$slots.default}
6
+ <div class="icon">
7
+ <slot />
8
+ </div>
9
+ {/if}
10
+ <div class="text">
11
+ {text}
12
+ </div>
13
+ </div>
14
+
15
+ <style>.empty {
16
+ display: flex;
17
+ flex-direction: column;
18
+ align-items: center;
19
+ justify-content: center;
20
+ text-align: center;
21
+ color: var(--color-text-secondary, rgba(150, 150, 150, 0.5));
22
+ font-size: 1.5rem;
23
+ font-weight: 500;
24
+ line-height: 2rem;
25
+ margin: 2rem 0;
26
+ }
27
+
28
+ .icon {
29
+ height: 2rem;
30
+ width: 2rem;
31
+ margin-bottom: 1rem;
32
+ }
33
+
34
+ .text {
35
+ font-size: 1.5rem;
36
+ font-weight: 500;
37
+ line-height: 2rem;
38
+ }</style>
@@ -0,0 +1,18 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ text?: string | undefined;
5
+ };
6
+ events: {
7
+ [evt: string]: CustomEvent<any>;
8
+ };
9
+ slots: {
10
+ default: {};
11
+ };
12
+ };
13
+ export type EmptyProps = typeof __propDef.props;
14
+ export type EmptyEvents = typeof __propDef.events;
15
+ export type EmptySlots = typeof __propDef.slots;
16
+ export default class Empty extends SvelteComponent<EmptyProps, EmptyEvents, EmptySlots> {
17
+ }
18
+ export {};
@@ -0,0 +1,12 @@
1
+ <svg
2
+ class="w-6 h-6 text-gray-800 dark:text-white"
3
+ aria-hidden="true"
4
+ xmlns="http://www.w3.org/2000/svg"
5
+ fill="currentColor"
6
+ viewBox="0 0 20 18"
7
+ >
8
+ <path
9
+ d="M4.09 7.586A1 1 0 0 1 5 7h13V6a2 2 0 0 0-2-2h-4.557L9.043.8a2.009 2.009 0 0 0-1.6-.8H2a2 2 0 0 0-2 2v14c.001.154.02.308.058.457L4.09 7.586Z"
10
+ />
11
+ <path d="M6.05 9 2 17.952c.14.031.281.047.424.048h12.95a.992.992 0 0 0 .909-.594L20 9H6.05Z" />
12
+ </svg>
@@ -0,0 +1,23 @@
1
+ /** @typedef {typeof __propDef.props} FolderOpenIconProps */
2
+ /** @typedef {typeof __propDef.events} FolderOpenIconEvents */
3
+ /** @typedef {typeof __propDef.slots} FolderOpenIconSlots */
4
+ export default class FolderOpenIcon extends SvelteComponent<{
5
+ [x: string]: never;
6
+ }, {
7
+ [evt: string]: CustomEvent<any>;
8
+ }, {}> {
9
+ }
10
+ export type FolderOpenIconProps = typeof __propDef.props;
11
+ export type FolderOpenIconEvents = typeof __propDef.events;
12
+ export type FolderOpenIconSlots = typeof __propDef.slots;
13
+ import { SvelteComponent } from "svelte";
14
+ declare const __propDef: {
15
+ props: {
16
+ [x: string]: never;
17
+ };
18
+ events: {
19
+ [evt: string]: CustomEvent<any>;
20
+ };
21
+ slots: {};
22
+ };
23
+ export {};
package/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ export { default as FormFooter } from './forms/form-footer.svelte';
20
20
  export { default as FormSection } from './forms/form-section.svelte';
21
21
  export { default as InfoBox } from './forms/info-box/info-box.svelte';
22
22
  export { default as UrlBox } from './forms/url-box/url-box.svelte';
23
+ export { default as NewOrExistingCombo } from './forms/combo/new-or-existing-combo.svelte';
23
24
  export { default as Card } from './generic/card/card.svelte';
24
25
  export { default as CardContainer } from './generic/card/card-container.svelte';
25
26
  export { default as Divider } from './generic/divider/divider.svelte';
@@ -36,6 +37,7 @@ export { default as Section } from './generic/section/section.svelte';
36
37
  export { default as Header } from './generic/header/header.svelte';
37
38
  export { default as Dot } from './generic/dot/dot.svelte';
38
39
  export { default as Notice } from './generic/notice/notice.svelte';
40
+ export { default as Empty } from './generic/empty/empty.svelte';
39
41
  export { default as FlexCol } from './layout/flex-col.svelte';
40
42
  export { default as FlexRow } from './layout/flex-row.svelte';
41
43
  export { default as FlexItem } from './layout/flex-item.svelte';
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ export { default as FormFooter } from './forms/form-footer.svelte';
21
21
  export { default as FormSection } from './forms/form-section.svelte';
22
22
  export { default as InfoBox } from './forms/info-box/info-box.svelte';
23
23
  export { default as UrlBox } from './forms/url-box/url-box.svelte';
24
+ export { default as NewOrExistingCombo } from './forms/combo/new-or-existing-combo.svelte';
24
25
  // Generic
25
26
  export { default as Card } from './generic/card/card.svelte';
26
27
  export { default as CardContainer } from './generic/card/card-container.svelte';
@@ -38,6 +39,7 @@ export { default as Section } from './generic/section/section.svelte';
38
39
  export { default as Header } from './generic/header/header.svelte';
39
40
  export { default as Dot } from './generic/dot/dot.svelte';
40
41
  export { default as Notice } from './generic/notice/notice.svelte';
42
+ export { default as Empty } from './generic/empty/empty.svelte';
41
43
  // Layout
42
44
  export { default as FlexCol } from './layout/flex-col.svelte';
43
45
  export { default as FlexRow } from './layout/flex-row.svelte';
@@ -1,9 +1,12 @@
1
- /// <reference types="svelte" />
2
- import type { TabStyle } from '../../types/generic.js';
3
- import type { Writable } from 'svelte/store';
1
+ import type { Subscribable } from '../../index.js';
2
+ export type TabStyle = 'traditional' | 'underline' | 'outline' | 'overline';
3
+ export type TabDefinition = {
4
+ id: string;
5
+ name: string;
6
+ };
4
7
  export interface TabContext {
5
- active: Writable<string | null>;
8
+ active: Subscribable<string | null>;
6
9
  style: TabStyle;
7
- squared: boolean;
10
+ register: (id: string, name: string, isActive: boolean) => void;
8
11
  }
9
12
  export declare const tabContext = "tabContext";
@@ -1,23 +1,157 @@
1
1
  <script>import { writable } from "svelte/store";
2
2
  import { setContext } from "svelte";
3
3
  import { tabContext } from "./tab-context.js";
4
+ import { subscribable } from "../../index.js";
4
5
  export let style = "traditional";
5
- export let squared = false;
6
+ const tabs = writable([]);
7
+ const register = (id, name, isActive) => {
8
+ tabs.update((value) => [...value, { id, name }]);
9
+ if (isActive)
10
+ active.set(id);
11
+ };
12
+ const active = writable(null);
13
+ const selectTab = (id) => {
14
+ active.set(id);
15
+ };
6
16
  const ctx = {
7
- active: writable(null),
17
+ active: subscribable(active),
8
18
  style,
9
- squared
19
+ register
10
20
  };
11
21
  setContext(tabContext, ctx);
12
22
  </script>
13
23
 
14
- <div>
15
- <slot />
16
- </div>
24
+ <section class="tab-group {style}">
25
+ <div class="tab-head">
26
+ <nav>
27
+ {#each $tabs as tab}
28
+ <li class={$active == tab.id ? 'active' : 'inactive'}>
29
+ <button on:click={() => selectTab(tab.id)}>
30
+ {tab.name}
31
+ </button>
32
+ </li>
33
+ {/each}
34
+ </nav>
35
+ </div>
36
+ <div class="tab-content">
37
+ <slot />
38
+ </div>
39
+ </section>
17
40
 
18
- <style>div {
41
+ <style>.tab-head {
42
+ height: 2rem;
19
43
  position: relative;
20
- display: block;
44
+ }
45
+ .tab-head nav {
46
+ display: flex;
47
+ flex-direction: row;
48
+ flex-wrap: nowrap;
49
+ justify-content: flex-start;
50
+ align-items: center;
51
+ box-sizing: border-box;
52
+ height: 2rem;
53
+ overflow: hidden;
21
54
  width: 100%;
22
- font-family: var(--base-font-family, sans-serif);
55
+ }
56
+ .tab-head li {
57
+ list-style: none;
58
+ margin: 0;
59
+ padding: 0;
60
+ }
61
+ .tab-head li.active button {
62
+ font-weight: 700;
63
+ cursor: default;
64
+ }
65
+ .tab-head button {
66
+ appearance: none;
67
+ border: none 0;
68
+ background: transparent;
69
+ line-height: 1.8rem;
70
+ height: 2rem;
71
+ padding-left: 1rem;
72
+ padding-right: 1rem;
73
+ cursor: pointer;
74
+ position: relative;
75
+ z-index: 2;
76
+ }
77
+ .tab-head button:focus {
78
+ outline: none;
79
+ }
80
+
81
+ .tab-content {
82
+ padding-top: 1rem;
83
+ padding-bottom: 1rem;
84
+ }
85
+
86
+ .traditional button {
87
+ border-radius: 0.5rem 0.5rem 0 0;
88
+ }
89
+ .traditional .inactive button {
90
+ background: var(--tab-traditional-inactive-bg, transparent);
91
+ color: var(--tab-traditional-inactive-fg, rgb(150, 150, 150));
92
+ }
93
+ .traditional .inactive button:hover {
94
+ background: var(--tab-traditional-hover-bg, transparent);
95
+ color: var(--tab-traditional-hover-fg, rgb(220, 220, 220));
96
+ }
97
+ .traditional .active button {
98
+ background: var(--tab-traditional-active-bg, rgb(220, 220, 230));
99
+ color: var(--tab-traditional-active-fg, rgb(50, 50, 50));
100
+ }
101
+ .traditional .tab-head {
102
+ border-bottom: solid 0.2rem var(--tab-traditional-border, rgb(220, 220, 230));
103
+ }
104
+
105
+ .underline button {
106
+ border-bottom: solid 0.2rem var(--tab-underline-inactive-fg, rgb(100, 100, 100));
107
+ }
108
+ .underline .tab-head {
109
+ border-bottom: solid 0.2rem var(--tab-underline-inactive-fg, rgb(100, 100, 100));
110
+ }
111
+ .underline .inactive button {
112
+ background: var(--tab-underline-inactive-bg, transparent);
113
+ color: var(--tab-underline-inactive-fg, rgb(150, 150, 150));
114
+ }
115
+ .underline .inactive button:hover {
116
+ background: var(--tab-underline-hover-bg, transparent);
117
+ color: var(--tab-underline-hover-fg, rgb(220, 220, 220));
118
+ }
119
+ .underline .active button {
120
+ color: var(--tab-underline-active-fg, rgb(255, 134, 78));
121
+ border-color: var(--tab-underline-active-fg, rgb(255, 134, 78));
122
+ background: var(--tab-underline-active-bg, rgb(80, 80, 80));
123
+ }
124
+
125
+ .outline button {
126
+ border-radius: 0.5rem 0.5rem 0 0;
127
+ }
128
+ .outline .tab-head {
129
+ border-bottom: solid 0.1rem var(--tab-outline-border, rgb(220, 220, 220));
130
+ }
131
+ .outline .inactive button {
132
+ color: var(--tab-outline-inactive-fg, rgb(120, 120, 120));
133
+ }
134
+ .outline .active button {
135
+ border-style: solid;
136
+ border-width: 0.1rem 0.1rem 0.1rem 0.1rem;
137
+ border-color: var(--tab-outline-border, rgb(220, 220, 220));
138
+ color: var(--base-fg, rgb(220, 220, 220));
139
+ border-bottom-color: var(--base-bg, rgb(50, 50, 50));
140
+ line-height: 1.7rem;
141
+ }
142
+
143
+ .overline .tab-head {
144
+ background: var(--tab-overline-bg, rgb(100, 100, 100));
145
+ }
146
+ .overline button {
147
+ border-top: solid 0.2rem;
148
+ }
149
+ .overline .active button {
150
+ color: var(--tab-overline-active-fg, rgb(255, 134, 78));
151
+ border-color: var(--tab-overline-active-fg, rgb(255, 134, 78));
152
+ background: var(--tab-overline-active-bg, rgb(50, 50, 50));
153
+ }
154
+ .overline .inactive button {
155
+ border-style: none;
156
+ color: var(--tab-overline-fg, rgb(180, 180, 180));
23
157
  }</style>
@@ -1,9 +1,8 @@
1
1
  import { SvelteComponent } from "svelte";
2
- import type { TabStyle } from '../../types/generic.js';
2
+ import { type TabStyle } from './tab-context.js';
3
3
  declare const __propDef: {
4
4
  props: {
5
5
  style?: TabStyle | undefined;
6
- squared?: boolean | undefined;
7
6
  };
8
7
  events: {
9
8
  [evt: string]: CustomEvent<any>;
@@ -1,130 +1,28 @@
1
1
  <script>import { createEventDispatcher, getContext, onDestroy } from "svelte";
2
2
  import { tabContext } from "./tab-context.js";
3
+ import { uniqueId } from "../../index.js";
3
4
  export let title;
4
5
  export let active = false;
5
6
  const dispatch = createEventDispatcher();
6
7
  const ctx = getContext(tabContext);
7
8
  const tabStyle = ctx.style || "traditional";
8
- const selectThisTab = () => {
9
- dispatch("selectTab", title);
10
- ctx.active.set(title);
11
- };
12
- if (active)
13
- selectThisTab();
14
- const unsubscribe = ctx.active.subscribe((value) => {
15
- active = value === title;
9
+ const id = uniqueId();
10
+ ctx.register(id, title, active);
11
+ const unsubscribe = ctx.active.subscribe((selectedId) => {
12
+ active = selectedId === id;
16
13
  });
17
- onDestroy(() => {
18
- unsubscribe();
19
- });
20
- $:
21
- classes = `${active ? "active" : "inactive"} ${tabStyle} ${ctx.squared ? "squared" : "rounded"}`;
14
+ onDestroy(() => unsubscribe());
22
15
  </script>
23
16
 
24
- <section class={classes}>
25
- <header class="tabTitle">
26
- <button type="button" on:click={selectThisTab}>
27
- {title}
28
- </button>
29
- </header>
30
- <div class="tabContent">
31
- {#if active}
32
- <slot />
33
- {/if}
34
- </div>
35
- </section>
36
-
37
- <style>section {
38
- display: inline;
39
- }
40
-
41
- .tabTitle {
42
- display: inline-block;
43
- cursor: pointer;
44
- height: 2.2rem;
45
- overflow: hidden;
46
- position: relative;
47
- z-index: 2;
48
- }
49
- .tabTitle button {
50
- appearance: none;
51
- background: transparent;
52
- border-style: solid;
53
- border-width: 0 0 0.2rem 0;
54
- border-color: transparent;
55
- border-radius: 0.5rem 0.5rem 0 0;
56
- color: inherit;
57
- cursor: pointer;
58
- width: 100%;
59
- height: 100%;
60
- font-size: 1rem;
61
- line-height: 1.8rem;
62
- height: 2.2rem;
63
- font-weight: 300;
64
- padding: 0 1rem;
65
- }
66
- .tabTitle button:focus {
67
- outline: none;
68
- }
17
+ <article class:active>
18
+ {#if active}
19
+ <slot />
20
+ {/if}
21
+ </article>
69
22
 
70
- .tabContent {
23
+ <style>article {
71
24
  display: none;
72
- width: 100%;
73
- position: absolute;
74
- top: 2rem;
75
- left: 0;
76
- border-top: solid 0.2rem var(--tab-content-border, rgb(220, 220, 230));
77
- padding-top: 1rem;
78
- font-size: 1rem;
79
25
  }
80
-
81
- .active button {
82
- font-weight: 700;
83
- cursor: default;
84
- }
85
-
86
- .inactive button {
87
- color: var(--tab-inactive-fg, #999);
88
- }
89
- .inactive button:hover {
90
- color: var(--tab-hover-fg, #ccc);
91
- }
92
-
93
- .active .tabContent {
26
+ article.active {
94
27
  display: block;
95
- }
96
-
97
- .squared button {
98
- border-radius: 0.2rem 0.2rem 0 0;
99
- }
100
-
101
- .traditional.inactive button {
102
- background: var(--tab-traditional-inactive-bg, transparent);
103
- color: var(--tab-traditional-inactive-fg, rgb(100, 100, 100));
104
- }
105
- .traditional.inactive button:hover {
106
- background: var(--tab-traditional-hover-bg, transparent);
107
- color: var(--tab-traditional-hover-fg, rgb(160, 160, 160));
108
- }
109
- .traditional.active button {
110
- background: var(--tab-traditional-active-bg, rgb(220, 220, 230));
111
- color: var(--tab-traditional-active-fg, rgb(51, 51, 51));
112
- }
113
-
114
- .underline.inactive button {
115
- background: var(--tab-underline-inactive-bg, transparent);
116
- color: var(--tab-underline-inactive-fg, rgb(100, 100, 100));
117
- }
118
- .underline.inactive button:hover {
119
- background: var(--tab-underline-hover-bg, transparent);
120
- color: var(--tab-underline-hover-fg, rgb(150, 150, 150));
121
- }
122
- .underline.active button {
123
- color: var(--tab-underline-active-fg, rgb(255, 134, 78));
124
- border-color: var(--tab-underline-active-fg, rgb(255, 134, 78));
125
- }
126
-
127
- .outline.active button {
128
- border-width: 0.1rem 0.1rem 0 0.1rem;
129
- border-color: var(--tab-content-border, rgb(220, 220, 230));
130
28
  }</style>
@@ -1,12 +1,13 @@
1
1
  <script>import { createEventDispatcher, setContext } from "svelte";
2
2
  import { writable } from "svelte/store";
3
3
  import { subscribable } from "../../helpers/subscribable.js";
4
- import Section from "../../generic/section/section.svelte";
5
4
  import Header from "../../generic/header/header.svelte";
6
5
  import Button from "../../forms/button/button.svelte";
7
6
  export let title;
8
7
  export let level = 3;
9
8
  export let disabled = false;
9
+ export let onNext = async () => [];
10
+ export let onSubmit = async () => [];
10
11
  let currentStep = 0;
11
12
  const dispatch = createEventDispatcher();
12
13
  const steps = {};
@@ -26,9 +27,19 @@ const register = (stepNumber, subtitle2) => {
26
27
  steps[stepNumber] = subtitle2;
27
28
  publish();
28
29
  };
29
- const next = () => {
30
+ const validate = async (callback) => {
31
+ disabled = true;
32
+ const errors = await callback();
33
+ disabled = false;
34
+ dispatch("errors", errors);
35
+ return errors;
36
+ };
37
+ const next = async () => {
30
38
  if (currentStep >= Object.values(steps).length || disabled)
31
39
  return;
40
+ const errors = await validate(() => onNext(currentStep));
41
+ if (errors.length)
42
+ return;
32
43
  currentStep++;
33
44
  dispatch("next", currentStep);
34
45
  publish();
@@ -40,9 +51,17 @@ const previous = () => {
40
51
  dispatch("previous", currentStep);
41
52
  publish();
42
53
  };
43
- const done = () => {
44
- disabled = true;
45
- dispatch("submit");
54
+ const reset = () => {
55
+ disabled = false;
56
+ currentStep = 1;
57
+ publish();
58
+ };
59
+ const done = async () => {
60
+ const errors = await validate(onSubmit);
61
+ if (errors.length)
62
+ return;
63
+ dispatch("done");
64
+ reset();
46
65
  };
47
66
  setContext("wizard", {
48
67
  state: subscribable(wizardStore),
@@ -92,4 +111,8 @@ footer {
92
111
  display: flex;
93
112
  justify-content: space-between;
94
113
  align-items: center;
114
+ flex-wrap: nowrap;
115
+ }
116
+ footer div {
117
+ width: 100%;
95
118
  }</style>
@@ -5,11 +5,14 @@ declare const __propDef: {
5
5
  title: string;
6
6
  level?: SectionLevel | undefined;
7
7
  disabled?: boolean | undefined;
8
+ onNext?: ((step: number) => Promise<string[]>) | undefined;
9
+ onSubmit?: (() => Promise<string[]>) | undefined;
8
10
  };
9
11
  events: {
10
- submit: CustomEvent<void>;
12
+ done: CustomEvent<void>;
11
13
  next: CustomEvent<number>;
12
14
  previous: CustomEvent<number>;
15
+ errors: CustomEvent<string[]>;
13
16
  } & {
14
17
  [evt: string]: CustomEvent<any>;
15
18
  };
@@ -8,6 +8,8 @@ import TableHeaderRow from "./table-header-row.svelte";
8
8
  import TableHeader from "./table-header.svelte";
9
9
  import TableRow from "./table-row.svelte";
10
10
  import Table from "./table.svelte";
11
+ import Empty from "../generic/empty/empty.svelte";
12
+ import FolderOpenIcon from "../icons/folder-open-icon.svelte";
11
13
  import Loading from "../placeholders/loading.svelte";
12
14
  import Text from "../typography/text.svelte";
13
15
  import TableCaption from "./table-caption.svelte";
@@ -72,7 +74,9 @@ $:
72
74
  {#if rows === undefined}
73
75
  <Loading />
74
76
  {:else}
75
- <Text>No data</Text>
77
+ <Empty>
78
+ <FolderOpenIcon />
79
+ </Empty>
76
80
  {/if}
77
81
  </div>
78
82
  </TableCell>
@@ -1,4 +1,3 @@
1
1
  export type SectionLevel = 1 | 2 | 3 | 4 | 5 | 6;
2
2
  export type HttpProtocol = 'http' | 'https';
3
3
  export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
4
- export type TabStyle = 'traditional' | 'underline' | 'outline';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sveltacular",
3
- "version": "0.0.40",
3
+ "version": "0.0.42",
4
4
  "description": "A Svelte component library",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",