parent
c79f7506c1
commit
21b2706cea
|
@ -0,0 +1,56 @@
|
||||||
|
<div class="skeleton">
|
||||||
|
<div class="children">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.skeleton {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
opacity: 0;
|
||||||
|
background-color: var(--spectrum-global-color-gray-300) !important;
|
||||||
|
border-radius: 7px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
animation: fadeIn 130ms ease 0s 1 normal forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.children {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
background-image: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(255, 255, 255, 0) 0,
|
||||||
|
rgba(255, 255, 255, 0.2) 20%,
|
||||||
|
rgba(255, 255, 255, 0.5) 60%,
|
||||||
|
rgba(255, 255, 255, 0)
|
||||||
|
);
|
||||||
|
animation: shimmer 2s infinite;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer {
|
||||||
|
100% {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -71,7 +71,8 @@
|
||||||
visibleRowCount,
|
visibleRowCount,
|
||||||
rowCount,
|
rowCount,
|
||||||
totalRowCount,
|
totalRowCount,
|
||||||
rowHeight
|
rowHeight,
|
||||||
|
loading
|
||||||
)
|
)
|
||||||
$: sortedRows = sortRows(rows, sortColumn, sortOrder)
|
$: sortedRows = sortRows(rows, sortColumn, sortOrder)
|
||||||
$: gridStyle = getGridStyle(fields, schema, showEditColumn)
|
$: gridStyle = getGridStyle(fields, schema, showEditColumn)
|
||||||
|
@ -120,8 +121,12 @@
|
||||||
visibleRowCount,
|
visibleRowCount,
|
||||||
rowCount,
|
rowCount,
|
||||||
totalRowCount,
|
totalRowCount,
|
||||||
rowHeight
|
rowHeight,
|
||||||
|
loading
|
||||||
) => {
|
) => {
|
||||||
|
if (loading) {
|
||||||
|
return `height: ${headerHeight + visibleRowCount * rowHeight}px;`
|
||||||
|
}
|
||||||
if (!rowCount || !visibleRowCount || totalRowCount <= rowCount) {
|
if (!rowCount || !visibleRowCount || totalRowCount <= rowCount) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -277,9 +282,11 @@
|
||||||
bind:offsetHeight={height}
|
bind:offsetHeight={height}
|
||||||
style={`--row-height: ${rowHeight}px; --header-height: ${headerHeight}px;`}
|
style={`--row-height: ${rowHeight}px; --header-height: ${headerHeight}px;`}
|
||||||
>
|
>
|
||||||
{#if !loaded}
|
{#if loading}
|
||||||
<div class="loading" style={heightStyle}>
|
<div class="loading" style={heightStyle}>
|
||||||
<ProgressCircle />
|
<slot name="loadingIndicator">
|
||||||
|
<ProgressCircle />
|
||||||
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="spectrum-Table" style={`${heightStyle}${gridStyle}`}>
|
<div class="spectrum-Table" style={`${heightStyle}${gridStyle}`}>
|
||||||
|
@ -438,9 +445,10 @@
|
||||||
|
|
||||||
/* Loading */
|
/* Loading */
|
||||||
.loading {
|
.loading {
|
||||||
display: grid;
|
display: flex;
|
||||||
place-items: center;
|
align-items: center;
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Table */
|
/* Table */
|
||||||
|
|
|
@ -4,6 +4,7 @@ import "./bbui.css"
|
||||||
import "@spectrum-css/icon/dist/index-vars.css"
|
import "@spectrum-css/icon/dist/index-vars.css"
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
|
export { default as Skeleton } from "./Skeleton/Skeleton.svelte"
|
||||||
export { default as Input } from "./Form/Input.svelte"
|
export { default as Input } from "./Form/Input.svelte"
|
||||||
export { default as Stepper } from "./Form/Stepper.svelte"
|
export { default as Stepper } from "./Form/Stepper.svelte"
|
||||||
export { default as TextArea } from "./Form/TextArea.svelte"
|
export { default as TextArea } from "./Form/TextArea.svelte"
|
||||||
|
|
|
@ -284,7 +284,7 @@
|
||||||
"editable": true,
|
"editable": true,
|
||||||
"size": {
|
"size": {
|
||||||
"width": 105,
|
"width": 105,
|
||||||
"height": 35
|
"height": 32
|
||||||
},
|
},
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
|
@ -683,7 +683,7 @@
|
||||||
"editable": true,
|
"editable": true,
|
||||||
"size": {
|
"size": {
|
||||||
"width": 400,
|
"width": 400,
|
||||||
"height": 30
|
"height": 24
|
||||||
},
|
},
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
|
@ -808,7 +808,7 @@
|
||||||
"editable": true,
|
"editable": true,
|
||||||
"size": {
|
"size": {
|
||||||
"width": 400,
|
"width": 400,
|
||||||
"height": 40
|
"height": 32
|
||||||
},
|
},
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
|
@ -2447,6 +2447,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"stringfield": {
|
"stringfield": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "Text Field",
|
"name": "Text Field",
|
||||||
"icon": "Text",
|
"icon": "Text",
|
||||||
"styles": [
|
"styles": [
|
||||||
|
@ -2455,7 +2456,7 @@
|
||||||
"editable": true,
|
"editable": true,
|
||||||
"size": {
|
"size": {
|
||||||
"width": 400,
|
"width": 400,
|
||||||
"height": 50
|
"height": 32
|
||||||
},
|
},
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
|
@ -2538,6 +2539,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"numberfield": {
|
"numberfield": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "Number Field",
|
"name": "Number Field",
|
||||||
"icon": "123",
|
"icon": "123",
|
||||||
"styles": [
|
"styles": [
|
||||||
|
@ -2652,6 +2654,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"optionsfield": {
|
"optionsfield": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "Options Picker",
|
"name": "Options Picker",
|
||||||
"icon": "Menu",
|
"icon": "Menu",
|
||||||
"styles": [
|
"styles": [
|
||||||
|
@ -2820,6 +2823,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"multifieldselect": {
|
"multifieldselect": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "Multi-select Picker",
|
"name": "Multi-select Picker",
|
||||||
"icon": "ViewList",
|
"icon": "ViewList",
|
||||||
"styles": [
|
"styles": [
|
||||||
|
@ -2982,12 +2986,13 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"booleanfield": {
|
"booleanfield": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "Checkbox",
|
"name": "Checkbox",
|
||||||
"icon": "SelectBox",
|
"icon": "SelectBox",
|
||||||
"editable": true,
|
"editable": true,
|
||||||
"size": {
|
"size": {
|
||||||
"width": 400,
|
"width": 20,
|
||||||
"height": 50
|
"height": 20
|
||||||
},
|
},
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
|
@ -3139,6 +3144,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"datetimefield": {
|
"datetimefield": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "Date Picker",
|
"name": "Date Picker",
|
||||||
"icon": "Date",
|
"icon": "Date",
|
||||||
"styles": [
|
"styles": [
|
||||||
|
@ -3220,6 +3226,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"codescanner": {
|
"codescanner": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "Barcode/QR Scanner",
|
"name": "Barcode/QR Scanner",
|
||||||
"icon": "Camera",
|
"icon": "Camera",
|
||||||
"styles": [
|
"styles": [
|
||||||
|
@ -3385,6 +3392,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"attachmentfield": {
|
"attachmentfield": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "Attachment",
|
"name": "Attachment",
|
||||||
"icon": "Attach",
|
"icon": "Attach",
|
||||||
"styles": [
|
"styles": [
|
||||||
|
@ -3443,6 +3451,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"relationshipfield": {
|
"relationshipfield": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "Relationship Picker",
|
"name": "Relationship Picker",
|
||||||
"icon": "TaskList",
|
"icon": "TaskList",
|
||||||
"styles": [
|
"styles": [
|
||||||
|
@ -3506,6 +3515,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"jsonfield": {
|
"jsonfield": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "JSON Field",
|
"name": "JSON Field",
|
||||||
"icon": "Brackets",
|
"icon": "Brackets",
|
||||||
"styles": [
|
"styles": [
|
||||||
|
@ -3707,6 +3717,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"table": {
|
"table": {
|
||||||
|
"skeleton": false,
|
||||||
"name": "Table",
|
"name": "Table",
|
||||||
"icon": "Table",
|
"icon": "Table",
|
||||||
"illegalChildren": [
|
"illegalChildren": [
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// to render this part of the block, taking advantage of binding enrichment
|
// to render this part of the block, taking advantage of binding enrichment
|
||||||
$: id = `${block.id}-${context ?? rand}`
|
$: id = `${block.id}-${context ?? rand}`
|
||||||
$: instance = {
|
$: instance = {
|
||||||
|
_blockElementHasChildren: $$slots?.default ?? false,
|
||||||
_component: `@budibase/standard-components/${type}`,
|
_component: `@budibase/standard-components/${type}`,
|
||||||
_id: id,
|
_id: id,
|
||||||
_instanceName: type[0].toUpperCase() + type.slice(1),
|
_instanceName: type[0].toUpperCase() + type.slice(1),
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
import Placeholder from "components/app/Placeholder.svelte"
|
import Placeholder from "components/app/Placeholder.svelte"
|
||||||
import ScreenPlaceholder from "components/app/ScreenPlaceholder.svelte"
|
import ScreenPlaceholder from "components/app/ScreenPlaceholder.svelte"
|
||||||
import ComponentPlaceholder from "components/app/ComponentPlaceholder.svelte"
|
import ComponentPlaceholder from "components/app/ComponentPlaceholder.svelte"
|
||||||
|
import Skeleton from "components/app/Skeleton.svelte"
|
||||||
|
|
||||||
export let instance = {}
|
export let instance = {}
|
||||||
export let isLayout = false
|
export let isLayout = false
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
|
|
||||||
// Get parent contexts
|
// Get parent contexts
|
||||||
const context = getContext("context")
|
const context = getContext("context")
|
||||||
|
const loading = getContext("loading")
|
||||||
const insideScreenslot = !!getContext("screenslot")
|
const insideScreenslot = !!getContext("screenslot")
|
||||||
|
|
||||||
// Create component context
|
// Create component context
|
||||||
|
@ -470,9 +472,21 @@
|
||||||
componentStore.actions.unregisterInstance(id)
|
componentStore.actions.unregisterInstance(id)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$: showSkeleton =
|
||||||
|
$loading &&
|
||||||
|
definition.name !== "Screenslot" &&
|
||||||
|
children.length === 0 &&
|
||||||
|
!instance._blockElementHasChildren &&
|
||||||
|
definition.skeleton !== false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if constructor && initialSettings && (visible || inSelectedPath) && !builderHidden}
|
{#if showSkeleton}
|
||||||
|
<Skeleton
|
||||||
|
height={initialSettings?.height || definition?.size?.height || 0}
|
||||||
|
width={initialSettings?.width || definition?.size?.width || 0}
|
||||||
|
/>
|
||||||
|
{:else if constructor && initialSettings && (visible || inSelectedPath) && !builderHidden}
|
||||||
<!-- The ID is used as a class because getElementsByClassName is O(1) -->
|
<!-- The ID is used as a class because getElementsByClassName is O(1) -->
|
||||||
<!-- and the performance matters for the selection indicators -->
|
<!-- and the performance matters for the selection indicators -->
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { writable } from "svelte/store"
|
||||||
import { setContext, getContext, onMount } from "svelte"
|
import { setContext, getContext, onMount } from "svelte"
|
||||||
import Router, { querystring } from "svelte-spa-router"
|
import Router, { querystring } from "svelte-spa-router"
|
||||||
import { routeStore, stateStore } from "stores"
|
import { routeStore, stateStore } from "stores"
|
||||||
|
@ -9,6 +10,9 @@
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
setContext("screenslot", true)
|
setContext("screenslot", true)
|
||||||
|
|
||||||
|
const loading = writable(false)
|
||||||
|
setContext("loading", loading)
|
||||||
|
|
||||||
// Only wrap this as an array to take advantage of svelte keying,
|
// Only wrap this as an array to take advantage of svelte keying,
|
||||||
// to ensure the svelte-spa-router is fully remounted when route config
|
// to ensure the svelte-spa-router is fully remounted when route config
|
||||||
// changes
|
// changes
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { writable } from "svelte/store"
|
||||||
import { ProgressCircle, Pagination } from "@budibase/bbui"
|
import { setContext, getContext } from "svelte"
|
||||||
|
import { Pagination } from "@budibase/bbui"
|
||||||
import { fetchData, LuceneUtils } from "@budibase/frontend-core"
|
import { fetchData, LuceneUtils } from "@budibase/frontend-core"
|
||||||
|
|
||||||
export let dataSource
|
export let dataSource
|
||||||
|
@ -10,6 +11,8 @@
|
||||||
export let limit
|
export let limit
|
||||||
export let paginate
|
export let paginate
|
||||||
|
|
||||||
|
const loading = writable(false)
|
||||||
|
|
||||||
const { styleable, Provider, ActionTypes, API } = getContext("sdk")
|
const { styleable, Provider, ActionTypes, API } = getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
|
||||||
|
@ -77,9 +80,13 @@
|
||||||
sortColumn: $fetch.sortColumn,
|
sortColumn: $fetch.sortColumn,
|
||||||
sortOrder: $fetch.sortOrder,
|
sortOrder: $fetch.sortOrder,
|
||||||
},
|
},
|
||||||
loaded: $fetch.loaded,
|
limit: limit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parentLoading = getContext("loading")
|
||||||
|
setContext("loading", loading)
|
||||||
|
$: loading.set($parentLoading || !$fetch.loaded)
|
||||||
|
|
||||||
const createFetch = datasource => {
|
const createFetch = datasource => {
|
||||||
return fetchData({
|
return fetchData({
|
||||||
API,
|
API,
|
||||||
|
@ -127,23 +134,17 @@
|
||||||
|
|
||||||
<div use:styleable={$component.styles} class="container">
|
<div use:styleable={$component.styles} class="container">
|
||||||
<Provider {actions} data={dataContext}>
|
<Provider {actions} data={dataContext}>
|
||||||
{#if !$fetch.loaded}
|
<slot />
|
||||||
<div class="loading">
|
{#if paginate && $fetch.supportsPagination}
|
||||||
<ProgressCircle />
|
<div class="pagination">
|
||||||
|
<Pagination
|
||||||
|
page={$fetch.pageNumber + 1}
|
||||||
|
hasPrevPage={$fetch.hasPrevPage}
|
||||||
|
hasNextPage={$fetch.hasNextPage}
|
||||||
|
goToPrevPage={fetch.prevPage}
|
||||||
|
goToNextPage={fetch.nextPage}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
|
||||||
<slot />
|
|
||||||
{#if paginate && $fetch.supportsPagination}
|
|
||||||
<div class="pagination">
|
|
||||||
<Pagination
|
|
||||||
page={$fetch.pageNumber + 1}
|
|
||||||
hasPrevPage={$fetch.hasPrevPage}
|
|
||||||
hasNextPage={$fetch.hasNextPage}
|
|
||||||
goToPrevPage={fetch.prevPage}
|
|
||||||
goToNextPage={fetch.nextPage}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
</Provider>
|
</Provider>
|
||||||
</div>
|
</div>
|
||||||
|
@ -155,13 +156,6 @@
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
.loading {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
.pagination {
|
.pagination {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
|
@ -12,22 +12,25 @@
|
||||||
|
|
||||||
const { Provider } = getContext("sdk")
|
const { Provider } = getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
const loading = getContext("loading")
|
||||||
|
|
||||||
$: rows = dataProvider?.rows ?? []
|
// If the parent DataProvider is loading, fill the rows array with a number of empty objects corresponding to the DataProvider's page size; this allows skeleton loader components to be rendered further down the tree.
|
||||||
$: loaded = dataProvider?.loaded ?? true
|
$: rows = $loading
|
||||||
|
? new Array(dataProvider.limit > 20 ? 20 : dataProvider.limit).fill({})
|
||||||
|
: dataProvider?.rows
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Container {direction} {hAlign} {vAlign} {gap} wrap>
|
<Container {direction} {hAlign} {vAlign} {gap} wrap>
|
||||||
{#if $component.empty}
|
{#if $component.empty}
|
||||||
<Placeholder />
|
<Placeholder />
|
||||||
{:else if rows.length > 0}
|
{:else if !$loading && rows.length === 0}
|
||||||
|
<div class="noRows"><i class="ri-list-check-2" />{noRowsMessage}</div>
|
||||||
|
{:else}
|
||||||
{#each rows as row, index}
|
{#each rows as row, index}
|
||||||
<Provider data={{ ...row, index }}>
|
<Provider data={{ ...row, index }}>
|
||||||
<slot />
|
<slot />
|
||||||
</Provider>
|
</Provider>
|
||||||
{/each}
|
{/each}
|
||||||
{:else if loaded && noRowsMessage}
|
|
||||||
<div class="noRows"><i class="ri-list-check-2" />{noRowsMessage}</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
import { Skeleton } from "@budibase/bbui"
|
||||||
|
|
||||||
|
const { styleable } = getContext("sdk")
|
||||||
|
const component = getContext("component")
|
||||||
|
|
||||||
|
export let height
|
||||||
|
export let width
|
||||||
|
|
||||||
|
let styles
|
||||||
|
|
||||||
|
$: {
|
||||||
|
styles = JSON.parse(JSON.stringify($component.styles))
|
||||||
|
|
||||||
|
if (!styles.normal.height && height) {
|
||||||
|
// The height and width props provided to this component can either be numbers or strings set by users (ex. '100%', '100px', '100'). A string of '100' wouldn't be a valid CSS property, but some of our components respect that input, so we need to handle it here also, hence the `!isNaN` check.
|
||||||
|
styles.normal.height = !isNaN(height) ? `${height}px` : height
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!styles.normal.width && width) {
|
||||||
|
styles.normal.width = !isNaN(width) ? `${width}px` : width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div use:styleable={styles}>
|
||||||
|
<Skeleton>
|
||||||
|
<slot />
|
||||||
|
</Skeleton>
|
||||||
|
</div>
|
|
@ -76,18 +76,26 @@
|
||||||
bind:fieldApi
|
bind:fieldApi
|
||||||
defaultValue={[]}
|
defaultValue={[]}
|
||||||
>
|
>
|
||||||
{#if fieldState}
|
<div class="minHeightWrapper">
|
||||||
<CoreDropzone
|
{#if fieldState}
|
||||||
value={fieldState.value}
|
<CoreDropzone
|
||||||
disabled={fieldState.disabled}
|
value={fieldState.value}
|
||||||
error={fieldState.error}
|
disabled={fieldState.disabled}
|
||||||
on:change={handleChange}
|
error={fieldState.error}
|
||||||
{processFiles}
|
on:change={handleChange}
|
||||||
{deleteAttachments}
|
{processFiles}
|
||||||
{handleFileTooLarge}
|
{deleteAttachments}
|
||||||
{handleTooManyFiles}
|
{handleFileTooLarge}
|
||||||
{maximum}
|
{handleTooManyFiles}
|
||||||
{extensions}
|
{maximum}
|
||||||
/>
|
{extensions}
|
||||||
{/if}
|
/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.minHeightWrapper {
|
||||||
|
min-height: 220px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import Placeholder from "../Placeholder.svelte"
|
import Placeholder from "../Placeholder.svelte"
|
||||||
import FieldGroupFallback from "./FieldGroupFallback.svelte"
|
import FieldGroupFallback from "./FieldGroupFallback.svelte"
|
||||||
|
import Skeleton from "../Skeleton.svelte"
|
||||||
import { getContext, onDestroy } from "svelte"
|
import { getContext, onDestroy } from "svelte"
|
||||||
|
|
||||||
export let label
|
export let label
|
||||||
|
@ -53,6 +54,8 @@
|
||||||
builderStore.actions.updateProp("label", e.target.textContent)
|
builderStore.actions.updateProp("label", e.target.textContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loading = getContext("loading")
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
fieldApi?.deregister()
|
fieldApi?.deregister()
|
||||||
unsubscribe?.()
|
unsubscribe?.()
|
||||||
|
@ -76,6 +79,10 @@
|
||||||
<div class="spectrum-Form-itemField">
|
<div class="spectrum-Form-itemField">
|
||||||
{#if !formContext}
|
{#if !formContext}
|
||||||
<Placeholder text="Form components need to be wrapped in a form" />
|
<Placeholder text="Form components need to be wrapped in a form" />
|
||||||
|
{:else if $loading}
|
||||||
|
<Skeleton>
|
||||||
|
<slot />
|
||||||
|
</Skeleton>
|
||||||
{:else if !fieldState}
|
{:else if !fieldState}
|
||||||
<Placeholder />
|
<Placeholder />
|
||||||
{:else if schemaType && schemaType !== type && type !== "options"}
|
{:else if schemaType && schemaType !== type && type !== "options"}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import { Table } from "@budibase/bbui"
|
import { Table, Skeleton } from "@budibase/bbui"
|
||||||
import SlotRenderer from "./SlotRenderer.svelte"
|
import SlotRenderer from "./SlotRenderer.svelte"
|
||||||
import { UnsortableTypes } from "../../../constants"
|
import { UnsortableTypes } from "../../../constants"
|
||||||
import { onDestroy } from "svelte"
|
import { onDestroy } from "svelte"
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
export let allowSelectRows
|
export let allowSelectRows
|
||||||
export let compact
|
export let compact
|
||||||
|
|
||||||
|
const loading = getContext("loading")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
const { styleable, getAction, ActionTypes, routeStore, rowSelectionStore } =
|
const { styleable, getAction, ActionTypes, routeStore, rowSelectionStore } =
|
||||||
getContext("sdk")
|
getContext("sdk")
|
||||||
|
@ -30,7 +31,6 @@
|
||||||
]
|
]
|
||||||
let selectedRows = []
|
let selectedRows = []
|
||||||
$: hasChildren = $component.children
|
$: hasChildren = $component.children
|
||||||
$: loading = dataProvider?.loading ?? false
|
|
||||||
$: data = dataProvider?.rows || []
|
$: data = dataProvider?.rows || []
|
||||||
$: fullSchema = dataProvider?.schema ?? {}
|
$: fullSchema = dataProvider?.schema ?? {}
|
||||||
$: fields = getFields(fullSchema, columns, showAutoColumns)
|
$: fields = getFields(fullSchema, columns, showAutoColumns)
|
||||||
|
@ -140,7 +140,7 @@
|
||||||
<Table
|
<Table
|
||||||
{data}
|
{data}
|
||||||
{schema}
|
{schema}
|
||||||
{loading}
|
loading={$loading}
|
||||||
{rowCount}
|
{rowCount}
|
||||||
{quiet}
|
{quiet}
|
||||||
{compact}
|
{compact}
|
||||||
|
@ -155,6 +155,9 @@
|
||||||
on:sort={onSort}
|
on:sort={onSort}
|
||||||
on:click={onClick}
|
on:click={onClick}
|
||||||
>
|
>
|
||||||
|
<div class="skeleton" slot="loadingIndicator">
|
||||||
|
<Skeleton />
|
||||||
|
</div>
|
||||||
<slot />
|
<slot />
|
||||||
</Table>
|
</Table>
|
||||||
{#if allowSelectRows && selectedRows.length}
|
{#if allowSelectRows && selectedRows.length}
|
||||||
|
@ -169,6 +172,11 @@
|
||||||
background-color: var(--spectrum-alias-background-color-secondary);
|
background-color: var(--spectrum-alias-background-color-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.skeleton {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.row-count {
|
.row-count {
|
||||||
margin-top: var(--spacing-l);
|
margin-top: var(--spacing-l);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue