Improve modal layout, improve modal button spacing, use rollup for building to expose multple BBUI entrypoints
This commit is contained in:
parent
4e2fceffcb
commit
10fe99346f
|
@ -2,38 +2,35 @@
|
|||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "1.58.13",
|
||||
"license": "AGPL-3.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/bbui.es.js"
|
||||
},
|
||||
"./internal": {
|
||||
"import": "./dist/internal.es.js"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
"./dist/style.css": "./dist/style.css"
|
||||
},
|
||||
"scripts": {
|
||||
"dev:builder": "vite build",
|
||||
"build": "vite build"
|
||||
"dev:builder": "rollup -cw",
|
||||
"build": "rollup -c"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^16.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^11.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.5",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"cross-env": "^7.0.2",
|
||||
"nollup": "^0.14.1",
|
||||
"postcss": "^8.2.9",
|
||||
"rollup": "^2.34.0",
|
||||
"rollup-plugin-copy": "^3.3.0",
|
||||
"rollup-plugin-delete": "^1.2.0",
|
||||
"rollup-plugin-hot": "^0.1.1",
|
||||
"rollup-plugin-node-builtins": "^2.1.2",
|
||||
"rollup": "^2.45.2",
|
||||
"rollup-plugin-postcss": "^4.0.0",
|
||||
"rollup-plugin-svelte-hot": "^0.11.0",
|
||||
"semantic-release": "^17.0.8",
|
||||
"svelte": "^3.37.0",
|
||||
"svench": "^0.0.10-7",
|
||||
"vite": "^2.1.5"
|
||||
"rollup-plugin-svelte": "^7.1.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"svelte": "^3.37.0"
|
||||
},
|
||||
"keywords": [
|
||||
"svelte"
|
||||
|
@ -50,20 +47,22 @@
|
|||
"@spectrum-css/checkbox": "^3.0.1",
|
||||
"@spectrum-css/dialog": "^3.0.1",
|
||||
"@spectrum-css/divider": "^1.0.1",
|
||||
"@spectrum-css/fieldlabel": "^3.0.1",
|
||||
"@spectrum-css/icon": "^3.0.1",
|
||||
"@spectrum-css/label": "^2.0.9",
|
||||
"@spectrum-css/link": "^3.1.1",
|
||||
"@spectrum-css/menu": "^3.0.1",
|
||||
"@spectrum-css/modal": "^3.0.1",
|
||||
"@spectrum-css/picker": "^1.0.1",
|
||||
"@spectrum-css/popover": "^3.0.1",
|
||||
"@spectrum-css/table": "^3.0.1",
|
||||
"@spectrum-css/textfield": "^3.0.1",
|
||||
"@spectrum-css/toast": "^3.0.1",
|
||||
"@spectrum-css/underlay": "^2.0.9",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
"dayjs": "^1.10.4",
|
||||
"markdown-it": "^12.0.4",
|
||||
"quill": "^1.3.7",
|
||||
"sirv-cli": "^0.4.6",
|
||||
"svelte-flatpickr": "^2.4.0",
|
||||
"svelte-portal": "^1.0.0",
|
||||
"turndown": "^7.0.0"
|
||||
|
|
|
@ -1,140 +1,30 @@
|
|||
import * as path from "path"
|
||||
import svelte from "rollup-plugin-svelte-hot"
|
||||
import svelte from "rollup-plugin-svelte"
|
||||
import resolve from "@rollup/plugin-node-resolve"
|
||||
import commonjs from "@rollup/plugin-commonjs"
|
||||
import json from "@rollup/plugin-json"
|
||||
import copy from "rollup-plugin-copy"
|
||||
import hmr from "rollup-plugin-hot"
|
||||
import del from "rollup-plugin-delete"
|
||||
import { terser } from "rollup-plugin-terser"
|
||||
import postcss from "rollup-plugin-postcss"
|
||||
import { plugin as Svench } from "svench/rollup"
|
||||
import builtins from "rollup-plugin-node-builtins"
|
||||
|
||||
const WATCH = !!process.env.ROLLUP_WATCH
|
||||
const SVENCH = !!process.env.SVENCH
|
||||
const HOT = WATCH
|
||||
const PRODUCTION = !WATCH
|
||||
|
||||
const svench = Svench({
|
||||
// The root dir that Svench will parse and watch.
|
||||
//
|
||||
// NOTE Watching the root of the project, to let Svench render *.md for us.
|
||||
//
|
||||
// NOTE By default, `node_modules` and `.git` dirs are ignored. This can be
|
||||
// customized by passing a function to `ignore` option. Default ignore is:
|
||||
//
|
||||
// ignore: path => /(?:^|\/)(?:node_modules|\.git)\//.test(path),
|
||||
//
|
||||
dir: ".",
|
||||
|
||||
// Make `src` dir a section (that is, it will always be "expanded" in the
|
||||
// menu).
|
||||
autoSections: ["src"],
|
||||
|
||||
// Use custom index.html
|
||||
index: {
|
||||
source: "public/index.html",
|
||||
},
|
||||
|
||||
extensions: [".svench", ".svench.svelte", ".svench.svx", ".md"],
|
||||
|
||||
serve: WATCH && {
|
||||
host: "0.0.0.0",
|
||||
port: 4242,
|
||||
public: "public",
|
||||
nollup: "0.0.0.0:42421",
|
||||
const makeConfig = ({ input, name }) => ({
|
||||
input,
|
||||
output: {
|
||||
sourcemap: true,
|
||||
format: "esm",
|
||||
file: `dist/${name}.es.js`,
|
||||
},
|
||||
plugins: [
|
||||
resolve(),
|
||||
commonjs(),
|
||||
svelte({
|
||||
emitCss: true,
|
||||
}),
|
||||
postcss(),
|
||||
terser(),
|
||||
json(),
|
||||
],
|
||||
})
|
||||
|
||||
// NOTE configs are in function form to avoid instantiating plugins of the
|
||||
// config that is not used for nothing (in particular, the HMR plugin launches
|
||||
// a dev server on startup, this is not desired when just building for prod)
|
||||
const configs = {
|
||||
svench: () => ({
|
||||
input: ".svench/svench.js",
|
||||
output: {
|
||||
format: "es",
|
||||
dir: "public/svench",
|
||||
},
|
||||
plugins: [
|
||||
builtins(),
|
||||
|
||||
// NOTE cleaning old builds is required to avoid serving stale static
|
||||
// files from a previous build instead of in-memory files from the dev/hmr
|
||||
// server
|
||||
del({
|
||||
targets: "public/svench/*",
|
||||
runOnce: true,
|
||||
}),
|
||||
|
||||
postcss({
|
||||
hot: HOT,
|
||||
extract: path.resolve("public/svench/theme.css"),
|
||||
sourceMap: true,
|
||||
}),
|
||||
|
||||
svench,
|
||||
|
||||
svelte({
|
||||
dev: !PRODUCTION,
|
||||
extensions: [".svelte", ".svench", ".svx", ".md"],
|
||||
// Svench's "combined" preprocessor wraps both Mdsvex preprocessors
|
||||
// (configured for Svench), and its own preprocessor (for static
|
||||
// analysis -- eg extract source from views)
|
||||
preprocess: svench.$.preprocess,
|
||||
hot: HOT && {
|
||||
optimistic: true,
|
||||
noPreserveState: false,
|
||||
},
|
||||
}),
|
||||
|
||||
resolve({ browser: true }),
|
||||
|
||||
commonjs(),
|
||||
json(),
|
||||
|
||||
HOT &&
|
||||
hmr({
|
||||
host: "0.0.0.0",
|
||||
public: "public",
|
||||
inMemory: true,
|
||||
compatModuleHot: !HOT, // for terser
|
||||
}),
|
||||
],
|
||||
|
||||
watch: {
|
||||
clearScreen: false,
|
||||
// buildDelay is needed to ensure Svench's code (routes) generator will
|
||||
// pick file changes before Rollup and prevent a double build (if Rollup
|
||||
// first sees a change to src/Foo.svench, then to Svench's routes.js)
|
||||
buildDelay: 100,
|
||||
},
|
||||
}),
|
||||
|
||||
lib: () => ({
|
||||
input: "src/index.js",
|
||||
output: [{ file: "dist/bundle.mjs", format: "es" }],
|
||||
plugins: [
|
||||
svelte({
|
||||
dev: !PRODUCTION,
|
||||
extensions: [".svelte"],
|
||||
emitCss: true,
|
||||
}),
|
||||
postcss(),
|
||||
copy({
|
||||
targets: [
|
||||
{
|
||||
src: ".svench/svench.css",
|
||||
dest: "public",
|
||||
rename: "global.css",
|
||||
},
|
||||
],
|
||||
}),
|
||||
resolve(),
|
||||
commonjs(),
|
||||
json(),
|
||||
],
|
||||
}),
|
||||
}
|
||||
|
||||
export default configs[SVENCH ? "svench" : "lib"]()
|
||||
export default [
|
||||
makeConfig({ input: "src/index.js", name: "bbui" }),
|
||||
makeConfig({ input: "src/Form/internal/index.js", name: "internal" }),
|
||||
]
|
||||
|
|
|
@ -4,16 +4,15 @@
|
|||
export let disabled = false
|
||||
|
||||
/** @type {('S', 'M', 'L', 'XL')} Size of button */
|
||||
export let size = "M";
|
||||
export let size = "M"
|
||||
|
||||
// Types
|
||||
export let cta, primary, secondary, warning, overBackground;
|
||||
export let cta, primary, secondary, warning, overBackground
|
||||
|
||||
export let quiet = false
|
||||
|
||||
export let icon = undefined;
|
||||
</script>
|
||||
|
||||
export let icon = undefined
|
||||
</script>
|
||||
|
||||
<button
|
||||
class:spectrum-Button--cta={cta}
|
||||
|
@ -26,15 +25,18 @@
|
|||
{disabled}
|
||||
on:click|preventDefault>
|
||||
{#if icon}
|
||||
<svg class="spectrum-Icon spectrum-Icon--size{size.toUpperCase()}" focusable="false" aria-hidden="true" aria-label="{icon}">
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-Icon--size{size.toUpperCase()}"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
aria-label={icon}>
|
||||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||
</svg>
|
||||
{/if}
|
||||
{#if $$slots}
|
||||
{#if $$slots}
|
||||
<span class="spectrum-Button-label"><slot /></span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<script>
|
||||
import "@spectrum-css/fieldlabel/dist/index-vars.css"
|
||||
import FieldLabel from "./FieldLabel.svelte"
|
||||
|
||||
export let id = null
|
||||
export let label = null
|
||||
export let labelPosition = "above"
|
||||
export let disabled = false
|
||||
export let error = null
|
||||
</script>
|
||||
|
||||
<div class="spectrum-Form-item" class:above={labelPosition === 'above'}>
|
||||
<FieldLabel forId={id} {label} position={labelPosition} />
|
||||
<div class="spectrum-Form-itemField">
|
||||
<slot />
|
||||
{#if error}
|
||||
<div class="error">{error}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.spectrum-Form-item.above {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.spectrum-Form-itemField {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: var(
|
||||
--spectrum-semantic-negative-color-default,
|
||||
var(--spectrum-global-color-red-500)
|
||||
);
|
||||
font-size: var(--spectrum-global-dimension-font-size-75);
|
||||
margin-top: var(--spectrum-global-dimension-size-75);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,26 @@
|
|||
<script>
|
||||
import "@spectrum-css/fieldlabel/dist/index-vars.css"
|
||||
|
||||
export let forId
|
||||
export let label
|
||||
export let position = "above"
|
||||
|
||||
$: className = position === "above" ? "" : `spectrum-FieldLabel--${position}`
|
||||
</script>
|
||||
|
||||
<label
|
||||
for={forId}
|
||||
class={`spectrum-FieldLabel spectrum-FieldLabel--sizeM spectrum-Form-itemLabel ${className}`}>
|
||||
{label || ''}
|
||||
</label>
|
||||
|
||||
<style>
|
||||
label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.spectrum-FieldLabel--right,
|
||||
.spectrum-FieldLabel--left {
|
||||
padding-right: var(--spectrum-global-dimension-size-200);
|
||||
}
|
||||
</style>
|
|
@ -1,190 +1,29 @@
|
|||
<script>
|
||||
import Field from "./Field.svelte"
|
||||
import TextField from "./internal/TextField.svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import Button from "../Button/Button.svelte"
|
||||
import Label from "../Styleguide/Label.svelte"
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let name = undefined
|
||||
export let label = undefined
|
||||
export let outline = false
|
||||
export let presentation = false
|
||||
export let thin = false
|
||||
export let extraThin = false
|
||||
export let large = false
|
||||
export let border = false
|
||||
export let edit = false
|
||||
export let value = null
|
||||
export let label = null
|
||||
export let labelPosition = "above"
|
||||
export let placeholder = null
|
||||
export let type = "text"
|
||||
export let disabled = false
|
||||
export let type = undefined
|
||||
export let placeholder = ""
|
||||
export let value = ""
|
||||
export let error = false
|
||||
export let validator = () => {}
|
||||
export let error = null
|
||||
|
||||
// This section handles the edit mode and dispatching of things to the parent when saved
|
||||
let editMode = false
|
||||
|
||||
const updateValue = e => {
|
||||
if (type === "number") {
|
||||
const num = parseFloat(e.target.value)
|
||||
value = isNaN(num) ? "" : num
|
||||
} else {
|
||||
value = e.target.value
|
||||
}
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
editMode = false
|
||||
dispatch("save", value)
|
||||
}
|
||||
|
||||
const enableEdit = () => {
|
||||
editMode = true
|
||||
const dispatch = createEventDispatcher()
|
||||
const onChange = e => {
|
||||
dispatch("change", e.detail)
|
||||
value = e.detail
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
{#if label || edit}
|
||||
<div class="label-container">
|
||||
{#if label}
|
||||
<Label extraSmall grey forAttr={name}>{label}</Label>
|
||||
{/if}
|
||||
{#if edit}
|
||||
<div class="controls">
|
||||
<Button small secondary disabled={editMode} on:click={enableEdit}>
|
||||
Edit
|
||||
</Button>
|
||||
<Button small blue disabled={!editMode} on:click={save}>Save</Button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<input
|
||||
class:outline
|
||||
class:presentation
|
||||
class:thin
|
||||
class:extraThin
|
||||
class:large
|
||||
class:border
|
||||
on:change
|
||||
on:input
|
||||
on:change={updateValue}
|
||||
on:input={updateValue}
|
||||
on:blur={updateValue}
|
||||
use:validator
|
||||
disabled={disabled || (edit && !editMode)}
|
||||
value={value == null ? '' : value}
|
||||
<Field {label} {labelPosition} {disabled} {error}>
|
||||
<TextField
|
||||
{error}
|
||||
{disabled}
|
||||
{value}
|
||||
{placeholder}
|
||||
{type}
|
||||
{name}
|
||||
{placeholder} />
|
||||
{#if error}
|
||||
<div class="error">{error}</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.label-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
margin-bottom: var(--spacing-s);
|
||||
}
|
||||
.label-container :global(label) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.controls {
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
grid-gap: 12px;
|
||||
margin-left: auto;
|
||||
padding-left: 12px;
|
||||
}
|
||||
.controls :global(button) {
|
||||
min-width: 100px;
|
||||
font-size: var(--font-size-s);
|
||||
border-radius: var(--rounded-small);
|
||||
}
|
||||
|
||||
input {
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
color: var(--ink);
|
||||
font-size: var(--font-size-s);
|
||||
border-radius: var(--border-radius-s);
|
||||
border: none;
|
||||
background-color: var(--grey-2);
|
||||
padding: var(--spacing-m);
|
||||
margin: 0;
|
||||
outline: none;
|
||||
font-family: var(--font-sans);
|
||||
border: var(--border-transparent);
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
input.presentation {
|
||||
background-color: var(--background);
|
||||
border: var(--background) 2px solid;
|
||||
}
|
||||
input.presentation:hover {
|
||||
background-color: var(--grey-2);
|
||||
border: var(--grey-4) 2px solid;
|
||||
}
|
||||
input.thin {
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
input.extraThin {
|
||||
font-size: var(--font-size-xs);
|
||||
padding: var(--spacing-s) var(--spacing-m);
|
||||
}
|
||||
input.large {
|
||||
font-size: var(--font-size-m);
|
||||
padding: var(--spacing-l);
|
||||
}
|
||||
input.border {
|
||||
border: var(--border-grey-2);
|
||||
}
|
||||
input.border:active {
|
||||
border: var(--border-blue);
|
||||
}
|
||||
input.border:focus {
|
||||
border: var(--border-blue);
|
||||
}
|
||||
input.outline {
|
||||
border: var(--border-light-2);
|
||||
background: var(--background);
|
||||
}
|
||||
input.outline:active {
|
||||
border: var(--border-blue);
|
||||
}
|
||||
input.outline:focus {
|
||||
border: var(--border-blue);
|
||||
}
|
||||
input:hover {
|
||||
border: var(--grey-4) 2px solid;
|
||||
}
|
||||
input::placeholder {
|
||||
color: var(--grey-6);
|
||||
}
|
||||
input:focus {
|
||||
border: var(--border-blue);
|
||||
}
|
||||
input:disabled {
|
||||
background: var(--grey-4);
|
||||
color: var(--grey-6);
|
||||
}
|
||||
|
||||
.error {
|
||||
margin-top: 10px;
|
||||
font-size: var(--font-size-xs);
|
||||
font-family: var(--font-sans);
|
||||
line-height: 1.17;
|
||||
color: var(--red);
|
||||
}
|
||||
</style>
|
||||
on:change={onChange} />
|
||||
</Field>
|
||||
|
|
|
@ -1,324 +1,33 @@
|
|||
<script>
|
||||
import Portal from "svelte-portal"
|
||||
import { afterUpdate } from "svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { fly } from "svelte/transition"
|
||||
import Label from "../Styleguide/Label.svelte"
|
||||
const xPath =
|
||||
"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
|
||||
import Multiselect from "./internal/Multiselect.svelte"
|
||||
import Field from "./Field.svelte"
|
||||
|
||||
import positionDropdown from "../Actions/position_dropdown"
|
||||
import clickOutside from "../Actions/click_outside"
|
||||
export let value = null
|
||||
export let label = undefined
|
||||
export let disabled = false
|
||||
export let labelPosition = "above"
|
||||
export let error = null
|
||||
export let placeholder = null
|
||||
export let options = []
|
||||
export let getOptionLabel = option => option
|
||||
export let getOptionValue = option => option
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let value = []
|
||||
export let label = undefined
|
||||
export let align = "left"
|
||||
export let secondary = false
|
||||
export let outline = false
|
||||
export let disabled = false
|
||||
export let placeholder = undefined
|
||||
export let extraThin = false
|
||||
|
||||
let options = []
|
||||
let optionsVisible = false
|
||||
let slot
|
||||
let anchor
|
||||
$: lookupMap = mapValues(value)
|
||||
$: selectedOptions = options.filter(option => lookupMap[option.value])
|
||||
|
||||
afterUpdate(() => {
|
||||
// Update available options
|
||||
const domOptions = Array.from(slot.querySelectorAll("option"))
|
||||
options = domOptions.map(option => ({
|
||||
value: option.value,
|
||||
name: option.textContent,
|
||||
}))
|
||||
})
|
||||
|
||||
function mapValues(value) {
|
||||
let map = {}
|
||||
if (value) {
|
||||
value.forEach(option => {
|
||||
map[option] = true
|
||||
})
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
function add(val) {
|
||||
value = [...value, val]
|
||||
dispatch("change", value)
|
||||
}
|
||||
|
||||
function remove(val) {
|
||||
value = value.filter(option => option !== val)
|
||||
dispatch("change", value)
|
||||
}
|
||||
|
||||
function showOptions(show) {
|
||||
optionsVisible = show
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
showOptions(!optionsVisible)
|
||||
}
|
||||
|
||||
function handleOptionMousedown(e) {
|
||||
const value = e.target.dataset.value
|
||||
if (value == null) {
|
||||
return
|
||||
}
|
||||
if (lookupMap[value]) {
|
||||
remove(value)
|
||||
} else {
|
||||
add(value)
|
||||
}
|
||||
const onChange = e => {
|
||||
dispatch("change", e.detail)
|
||||
value = e.detail
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if label}
|
||||
<Label extraSmall grey>{label}</Label>
|
||||
{/if}
|
||||
<div class="multiselect" bind:this={anchor}>
|
||||
<div class="tokens-wrapper">
|
||||
<div
|
||||
class="tokens"
|
||||
class:outline
|
||||
class:disabled
|
||||
class:secondary
|
||||
class:extraThin
|
||||
class:optionsVisible
|
||||
on:click|self={handleClick}
|
||||
class:empty={!value || !value.length}>
|
||||
{#each selectedOptions as option}
|
||||
<div
|
||||
class="token"
|
||||
class:extraThin
|
||||
data-id={option.value}
|
||||
on:click|self={handleClick}>
|
||||
<span>{option.name}</span>
|
||||
<div
|
||||
class="token-remove"
|
||||
title="Remove {option.name}"
|
||||
on:click={() => remove(option.value)}>
|
||||
<svg
|
||||
class="icon-clear"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24">
|
||||
<path d={xPath} />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{#if !value || !value.length}
|
||||
{#if placeholder && placeholder.length}
|
||||
<div class:disabled class="placeholder">{placeholder}</div>
|
||||
{:else}
|
||||
<div class="placeholder"> </div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<select bind:this={slot} type="multiple" class="hidden">
|
||||
<slot />
|
||||
</select>
|
||||
|
||||
{#if optionsVisible}
|
||||
<Portal>
|
||||
<ul
|
||||
class="options"
|
||||
use:positionDropdown={{ anchor, align }}
|
||||
use:clickOutside={() => showOptions(false)}
|
||||
transition:fly={{ duration: 200, y: 5 }}
|
||||
on:mousedown|preventDefault={handleOptionMousedown}>
|
||||
{#each options as option}
|
||||
<li
|
||||
class:selected={lookupMap[option.value]}
|
||||
data-value={option.value}>
|
||||
{option.name}
|
||||
</li>
|
||||
{/each}
|
||||
{#if !options.length}
|
||||
<li class="no-results">No results</li>
|
||||
{/if}
|
||||
</ul>
|
||||
</Portal>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.multiselect {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
font-family: var(--font-sans);
|
||||
min-width: 0;
|
||||
}
|
||||
.multiselect:hover {
|
||||
border-bottom-color: hsl(0, 0%, 50%);
|
||||
}
|
||||
|
||||
.tokens-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.tokens {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
position: relative;
|
||||
width: 0;
|
||||
flex: 1 1 auto;
|
||||
background-color: var(--background);
|
||||
border-radius: var(--border-radius-m);
|
||||
padding: 0 var(--spacing-m) calc(var(--spacing-m) - var(--spacing-xs))
|
||||
calc(var(--spacing-m) / 2);
|
||||
border: var(--border-transparent);
|
||||
}
|
||||
.tokens.disabled {
|
||||
background-color: var(--grey-4);
|
||||
pointer-events: none;
|
||||
}
|
||||
.tokens.outline {
|
||||
border: var(--border-dark);
|
||||
}
|
||||
.tokens.secondary {
|
||||
background-color: var(--grey-2);
|
||||
}
|
||||
.tokens.extraThin {
|
||||
padding: 0 var(--spacing-m) calc(var(--spacing-s) - var(--spacing-xs))
|
||||
calc(var(--spacing-m) / 2);
|
||||
}
|
||||
.tokens:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
.tokens.optionsVisible {
|
||||
border: var(--border-blue);
|
||||
}
|
||||
.tokens.empty {
|
||||
padding: var(--spacing-m);
|
||||
font-size: var(--font-size-xs);
|
||||
user-select: none;
|
||||
}
|
||||
.tokens.empty.extraThin {
|
||||
padding: var(--spacing-s) var(--spacing-m);
|
||||
}
|
||||
.tokens::after {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.token {
|
||||
font-size: var(--font-size-xs);
|
||||
background-color: var(--ink);
|
||||
color: var(--background);
|
||||
border-radius: var(--border-radius-l);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin: calc(var(--spacing-m) - var(--spacing-xs)) 0 0
|
||||
calc(var(--spacing-m) / 2);
|
||||
max-height: 1.3rem;
|
||||
padding: var(--spacing-xs) var(--spacing-s);
|
||||
transition: background-color 0.3s;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.token.extraThin {
|
||||
margin: calc(var(--spacing-s) - var(--spacing-xs)) 0 0
|
||||
calc(var(--spacing-m) / 2);
|
||||
}
|
||||
.token span {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.token .token-remove {
|
||||
align-items: center;
|
||||
background-color: var(--grey-7);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
margin: calc(-1 * var(--spacing-xs)) 0 calc(-1 * var(--spacing-xs))
|
||||
var(--spacing-xs);
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.token path {
|
||||
fill: var(--background);
|
||||
}
|
||||
.token .token-remove:hover {
|
||||
background-color: var(--grey-6);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
pointer-events: none;
|
||||
color: var(--ink);
|
||||
}
|
||||
.placeholder.disabled {
|
||||
color: var(--grey-6);
|
||||
}
|
||||
|
||||
.icon-clear path {
|
||||
fill: white;
|
||||
}
|
||||
.options {
|
||||
left: 0;
|
||||
list-style: none;
|
||||
margin-block-end: 0;
|
||||
margin-block-start: 0;
|
||||
overflow-y: auto;
|
||||
padding-inline-start: 0;
|
||||
position: absolute;
|
||||
border: var(--border-dark);
|
||||
border-radius: var(--border-radius-m);
|
||||
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.15);
|
||||
margin: var(--spacing-xs) 0;
|
||||
padding: var(--spacing-s) 0;
|
||||
background-color: var(--background);
|
||||
max-height: 200px;
|
||||
}
|
||||
li {
|
||||
cursor: pointer;
|
||||
padding: var(--spacing-s) var(--spacing-m);
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--ink);
|
||||
}
|
||||
li.selected {
|
||||
background-color: var(--blue);
|
||||
color: white;
|
||||
}
|
||||
li:not(.selected):hover {
|
||||
background-color: var(--grey-1);
|
||||
}
|
||||
li.no-results:hover {
|
||||
background-color: white;
|
||||
cursor: initial;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
}
|
||||
</style>
|
||||
<Field {label} {labelPosition} {disabled} {error}>
|
||||
<Multiselect
|
||||
{error}
|
||||
{disabled}
|
||||
{value}
|
||||
{options}
|
||||
{placeholder}
|
||||
{getOptionLabel}
|
||||
{getOptionValue}
|
||||
on:change={onChange} />
|
||||
</Field>
|
||||
|
|
|
@ -1,95 +1,33 @@
|
|||
<script>
|
||||
import Icon from "../Icons/Icon.svelte"
|
||||
import Label from "../Styleguide/Label.svelte"
|
||||
import Field from "./Field.svelte"
|
||||
import Select from "./internal/Select.svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
export let value = ""
|
||||
export let name = undefined
|
||||
export let value = null
|
||||
export let label = undefined
|
||||
export let thin = false
|
||||
export let extraThin = false
|
||||
export let secondary = false
|
||||
export let outline = false
|
||||
export let disabled = false
|
||||
export let labelPosition = "above"
|
||||
export let error = null
|
||||
export let placeholder = null
|
||||
export let options = []
|
||||
export let getOptionLabel = option => option
|
||||
export let getOptionValue = option => option
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const onChange = e => {
|
||||
dispatch("change", e.detail)
|
||||
value = e.detail
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if label}
|
||||
<Label extraSmall grey forAttr={name}>{label}</Label>
|
||||
{/if}
|
||||
<div class="relative">
|
||||
<select
|
||||
{name}
|
||||
class:thin
|
||||
class:extraThin
|
||||
class:secondary
|
||||
class:outline
|
||||
{disabled}
|
||||
on:change
|
||||
bind:value>
|
||||
<slot />
|
||||
</select>
|
||||
<div class="pointer">
|
||||
<Icon name="arrowdown" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
select {
|
||||
font-family: var(--font-sans);
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
border-radius: var(--border-radius-s);
|
||||
border: none;
|
||||
text-align: left;
|
||||
color: var(--ink);
|
||||
font-size: var(--font-size-s);
|
||||
padding: var(--spacing-m) 2rem var(--spacing-m) var(--spacing-m) !important;
|
||||
appearance: none !important;
|
||||
-webkit-appearance: none !important;
|
||||
-moz-appearance: none !important;
|
||||
align-items: center;
|
||||
white-space: pre;
|
||||
outline: none;
|
||||
border: var(--border-transparent);
|
||||
background-color: var(--background);
|
||||
}
|
||||
select.thin {
|
||||
padding: var(--spacing-m);
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
select.extraThin {
|
||||
padding: var(--spacing-s) 2rem var(--spacing-s) var(--spacing-m) !important;
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
select.secondary {
|
||||
background: var(--grey-2);
|
||||
}
|
||||
select.outline {
|
||||
border: var(--border-light-2);
|
||||
}
|
||||
select:focus {
|
||||
border: var(--border-blue);
|
||||
}
|
||||
select:disabled {
|
||||
background: var(--grey-4);
|
||||
color: var(--grey-6);
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative !important;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
right: 0 !important;
|
||||
top: 0 !important;
|
||||
bottom: 0 !important;
|
||||
position: absolute !important;
|
||||
pointer-events: none !important;
|
||||
padding-left: 0.5rem !important;
|
||||
align-items: center !important;
|
||||
display: flex !important;
|
||||
color: var(--ink);
|
||||
}
|
||||
</style>
|
||||
<Field {label} {labelPosition} {disabled} {error}>
|
||||
<Select
|
||||
{error}
|
||||
{disabled}
|
||||
{value}
|
||||
{options}
|
||||
{placeholder}
|
||||
{getOptionLabel}
|
||||
{getOptionValue}
|
||||
on:change={onChange} />
|
||||
</Field>
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<script>
|
||||
import Picker from "./Picker.svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
export let value = []
|
||||
export let fieldId = null
|
||||
export let placeholder = null
|
||||
export let disabled = false
|
||||
export let error = null
|
||||
export let options = []
|
||||
export let getOptionLabel = option => option
|
||||
export let getOptionValue = option => option
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
$: fieldText = getFieldText(value)
|
||||
$: valueLookupMap = getValueLookupMap(value)
|
||||
$: isOptionSelected = option => valueLookupMap[option] === true
|
||||
|
||||
const getFieldText = value => {
|
||||
if (value?.length) {
|
||||
const count = value?.length ?? 0
|
||||
return `${count} selected option${count === 1 ? "" : "s"}`
|
||||
} else {
|
||||
return placeholder || "Choose some options"
|
||||
}
|
||||
}
|
||||
|
||||
const getValueLookupMap = value => {
|
||||
let map = {}
|
||||
if (value?.length) {
|
||||
value.forEach(option => {
|
||||
const optionValue = getOptionValue(option)
|
||||
if (optionValue) {
|
||||
map[optionValue] = true
|
||||
}
|
||||
})
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
const toggleOption = option => {
|
||||
if (valueLookupMap[option]) {
|
||||
const filtered = value.filter(option => option !== id)
|
||||
dispatch("change", filtered)
|
||||
} else {
|
||||
dispatch("change", [...value, option])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Picker
|
||||
{fieldId}
|
||||
{error}
|
||||
{disabled}
|
||||
{fieldText}
|
||||
{options}
|
||||
isPlaceholder={!value?.length}
|
||||
{isOptionSelected}
|
||||
{getOptionLabel}
|
||||
{getOptionValue}
|
||||
onSelectOption={toggleOption} />
|
|
@ -0,0 +1,109 @@
|
|||
<script>
|
||||
import "@spectrum-css/picker/dist/index-vars.css"
|
||||
import "@spectrum-css/popover/dist/index-vars.css"
|
||||
import "@spectrum-css/menu/dist/index-vars.css"
|
||||
import { fly } from "svelte/transition"
|
||||
|
||||
export let fieldId = null
|
||||
export let disabled = false
|
||||
export let error = null
|
||||
export let fieldText = ""
|
||||
export let isPlaceholder = false
|
||||
export let placeholderOption = null
|
||||
export let options = []
|
||||
export let isOptionSelected = () => false
|
||||
export let onSelectOption = () => {}
|
||||
export let getOptionLabel = option => option
|
||||
export let getOptionValue = option => option
|
||||
export let open = false
|
||||
</script>
|
||||
|
||||
<button
|
||||
id={fieldId}
|
||||
class="spectrum-Picker spectrum-Picker--sizeM"
|
||||
{disabled}
|
||||
class:is-invalid={!!error}
|
||||
class:is-open={open}
|
||||
aria-haspopup="listbox"
|
||||
on:click={() => (open = true)}>
|
||||
<span class="spectrum-Picker-label" class:is-placeholder={isPlaceholder}>
|
||||
{fieldText}
|
||||
</span>
|
||||
{#if error}
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
aria-label="Folder">
|
||||
<use xlink:href="#spectrum-icon-18-Alert" />
|
||||
</svg>
|
||||
{/if}
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true">
|
||||
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
||||
</svg>
|
||||
</button>
|
||||
{#if open}
|
||||
<div class="overlay" on:mousedown|self={() => (open = false)} />
|
||||
<div
|
||||
transition:fly={{ y: -20, duration: 200 }}
|
||||
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open">
|
||||
<ul class="spectrum-Menu" role="listbox">
|
||||
{#if placeholderOption}
|
||||
<li
|
||||
class="spectrum-Menu-item"
|
||||
class:is-selected={isPlaceholder}
|
||||
role="option"
|
||||
aria-selected="true"
|
||||
tabindex="0"
|
||||
on:click={() => onSelectOption(null)}>
|
||||
<span class="spectrum-Menu-itemLabel">{placeholderOption}</span>
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true">
|
||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||
</svg>
|
||||
</li>
|
||||
{/if}
|
||||
{#each options as option}
|
||||
<li
|
||||
class="spectrum-Menu-item"
|
||||
class:is-selected={isOptionSelected(getOptionValue(option))}
|
||||
role="option"
|
||||
aria-selected="true"
|
||||
tabindex="0"
|
||||
on:click={() => onSelectOption(getOptionValue(option))}>
|
||||
<span class="spectrum-Menu-itemLabel">{getOptionLabel(option)}</span>
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true">
|
||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||
</svg>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
z-index: 999;
|
||||
}
|
||||
.spectrum-Popover {
|
||||
max-height: 240px;
|
||||
width: 100%;
|
||||
z-index: 999;
|
||||
}
|
||||
.spectrum-Picker {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,42 @@
|
|||
<script>
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import Picker from "./Picker.svelte"
|
||||
|
||||
export let value = null
|
||||
export let fieldId = null
|
||||
export let placeholder = null
|
||||
export let disabled = false
|
||||
export let error = null
|
||||
export let options = []
|
||||
export let getOptionLabel = option => option
|
||||
export let getOptionValue = option => option
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let open = false
|
||||
$: placeholderText = placeholder || "Choose an option"
|
||||
$: isNull = value == null || value === ""
|
||||
$: selectedOption = options.find(option => getOptionValue(option) === value)
|
||||
$: selectedLabel = selectedOption
|
||||
? getOptionLabel(selectedOption)
|
||||
: placeholderText
|
||||
$: fieldText = isNull ? placeholderText : selectedLabel
|
||||
|
||||
const selectOption = value => {
|
||||
dispatch("change", value)
|
||||
open = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<Picker
|
||||
bind:open
|
||||
{fieldId}
|
||||
{error}
|
||||
{disabled}
|
||||
{fieldText}
|
||||
{options}
|
||||
{getOptionLabel}
|
||||
{getOptionValue}
|
||||
isPlaceholder={isNull}
|
||||
placeholderOption={placeholderText}
|
||||
isOptionSelected={option => option === value}
|
||||
onSelectOption={selectOption} />
|
|
@ -0,0 +1,60 @@
|
|||
<script>
|
||||
import "@spectrum-css/textfield/dist/index-vars.css"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
export let value = ""
|
||||
export let placeholder = ""
|
||||
export let type = "text"
|
||||
export let disabled = false
|
||||
export let error = null
|
||||
export let id = null
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const updateValue = value => {
|
||||
if (type === "number") {
|
||||
const float = parseFloat(value)
|
||||
value = isNaN(float) ? null : float
|
||||
}
|
||||
dispatch("change", value)
|
||||
}
|
||||
|
||||
const onBlur = event => {
|
||||
updateValue(event.target.value)
|
||||
}
|
||||
|
||||
const updateValueOnEnter = event => {
|
||||
if (event.key === "Enter") {
|
||||
updateValue(event.target.value)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="spectrum-Textfield"
|
||||
class:is-invalid={!!error}
|
||||
class:is-disabled={disabled}>
|
||||
{#if error}
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true">
|
||||
<use xlink:href="#spectrum-icon-18-Alert" />
|
||||
</svg>
|
||||
{/if}
|
||||
<input
|
||||
on:keyup={updateValueOnEnter}
|
||||
{disabled}
|
||||
{id}
|
||||
value={value || ''}
|
||||
placeholder={placeholder || ''}
|
||||
on:blur={onBlur}
|
||||
{type}
|
||||
class="spectrum-Textfield-input" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.spectrum-Textfield {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,2 @@
|
|||
export { default as TextField } from "./TextField.svelte"
|
||||
export { default as Select } from "./Select.svelte"
|
|
@ -38,12 +38,56 @@
|
|||
|
||||
{#if visible}
|
||||
<Portal target=".modal-container">
|
||||
<div class="spectrum-Underlay is-open" transition:fade={{ duration: 200 }} on:click|self={hide}>
|
||||
<div class="spectrum-Modal-wrapper">
|
||||
<div class="spectrum-Modal is-open" transition:fly={{ y: 30, duration: 200 }}>
|
||||
<slot />
|
||||
<div
|
||||
class="spectrum-Underlay is-open"
|
||||
transition:fade={{ duration: 200 }}
|
||||
on:click|self={hide}>
|
||||
<div class="modal-wrapper" on:click|self={hide}>
|
||||
<div class="modal-inner-wrapper" on:click|self={hide}>
|
||||
<div
|
||||
class="spectrum-Modal is-open"
|
||||
transition:fly={{ y: 30, duration: 200 }}>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Portal>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.spectrum-Underlay {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 999;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.modal-wrapper {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
-moz-box-pack: center;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
max-height: 100%;
|
||||
}
|
||||
.modal-inner-wrapper {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
-moz-box-pack: center;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.spectrum-Modal {
|
||||
overflow: visible;
|
||||
max-height: none;
|
||||
margin: 40px 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -29,36 +29,37 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="spectrum-Dialog spectrum-Dialog--{size}" role="dialog" tabindex="-1" aria-modal="true">
|
||||
<div
|
||||
class="spectrum-Dialog spectrum-Dialog--{size}"
|
||||
role="dialog"
|
||||
tabindex="-1"
|
||||
aria-modal="true">
|
||||
<div class="spectrum-Dialog-grid">
|
||||
<h1 class="spectrum-Dialog-heading">{title}</h1>
|
||||
<hr class="spectrum-Divider spectrum-Divider--sizeS spectrum-Divider--horizontal spectrum-Dialog-divider">
|
||||
|
||||
<hr
|
||||
class="spectrum-Divider spectrum-Divider--sizeS spectrum-Divider--horizontal spectrum-Dialog-divider" />
|
||||
|
||||
<!-- TODO: Remove content-grid class once Layout components are in bbui -->
|
||||
<section class="spectrum-Dialog-content content-grid">
|
||||
<slot />
|
||||
</section>
|
||||
{#if showCancelButton || showConfirmButton}
|
||||
<div class="spectrum-ButtonGroup spectrum-Dialog-buttonGroup spectrum-Dialog-buttonGroup--noFooter">
|
||||
<!-- <footer class="footer-content">
|
||||
<slot name="footer" />
|
||||
</footer> -->
|
||||
<div class="spectrum-ButtonGroup-item">
|
||||
<slot name="footer" />
|
||||
{#if showCancelButton}
|
||||
<Button secondary on:click={hide}>{cancelText}</Button>
|
||||
{/if}
|
||||
{#if showConfirmButton}
|
||||
<Button
|
||||
<div
|
||||
class="spectrum-ButtonGroup spectrum-Dialog-buttonGroup spectrum-Dialog-buttonGroup--noFooter">
|
||||
<slot name="footer" />
|
||||
{#if showCancelButton}
|
||||
<Button group secondary on:click={hide}>{cancelText}</Button>
|
||||
{/if}
|
||||
{#if showConfirmButton}
|
||||
<Button
|
||||
group
|
||||
cta
|
||||
primary
|
||||
{...$$restProps}
|
||||
disabled={confirmDisabled}
|
||||
on:click={confirm}>
|
||||
{confirmText}
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{...$$restProps}
|
||||
disabled={confirmDisabled}
|
||||
on:click={confirm}>
|
||||
{confirmText}
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if showCloseIcon}
|
||||
|
@ -69,7 +70,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
.content-grid {
|
||||
display: grid;
|
||||
|
@ -78,6 +78,14 @@
|
|||
color: var(--ink);
|
||||
}
|
||||
|
||||
.spectrum-Dialog-content {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.spectrum-Dialog-buttonGroup {
|
||||
gap: var(--spectrum-global-dimension-static-size-200);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
@ -95,27 +103,4 @@
|
|||
.close-icon :global(svg) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
export let schema = {}
|
||||
export let showAutoColumns = false
|
||||
export let rowCount = 0
|
||||
export let quiet = true
|
||||
export let quiet = false
|
||||
export let loading = false
|
||||
export let allowSelectRows = true
|
||||
export let allowEditRows = true
|
||||
|
@ -311,8 +311,6 @@
|
|||
height: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
border: 1px solid
|
||||
var(--spectrum-table-border-color, var(--spectrum-alias-border-color-mid)) !important;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--spectrum-global-color-gray-400)
|
||||
var(--spectrum-alias-background-color-primary);
|
||||
|
@ -421,14 +419,16 @@
|
|||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
border-bottom: none !important;
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-top: 1px solid
|
||||
var(--spectrum-table-border-color, var(--spectrum-alias-border-color-mid)) !important;
|
||||
}
|
||||
tr:first-child td {
|
||||
border-top: none !important;
|
||||
}
|
||||
tr:last-child td {
|
||||
border-bottom: 1px solid
|
||||
var(--spectrum-table-border-color, var(--spectrum-alias-border-color-mid)) !important;
|
||||
}
|
||||
.container:not(.quiet) td.spectrum-Table-cell--divider {
|
||||
width: 1px;
|
||||
border-right: 1px solid
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
import svelte from "@sveltejs/vite-plugin-svelte"
|
||||
|
||||
export default ({ mode }) => {
|
||||
const isProduction = mode === "production"
|
||||
return {
|
||||
build: {
|
||||
lib: {
|
||||
entry: "src/index.js",
|
||||
name: "bbui",
|
||||
formats: ["es"],
|
||||
},
|
||||
minify: isProduction,
|
||||
},
|
||||
plugins: [svelte()],
|
||||
resolve: {
|
||||
dedupe: ["svelte", "svelte/internal"],
|
||||
},
|
||||
rollupOptions: {
|
||||
external: ["svelte", "svelte/internal"],
|
||||
},
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue