Merge branch 'next' of github.com:Budibase/budibase into feature/password-reset
This commit is contained in:
commit
b01da0aad5
|
@ -15,6 +15,22 @@
|
||||||
"created_at": "2021-04-14T16:20:04Z",
|
"created_at": "2021-04-14T16:20:04Z",
|
||||||
"repoId": 190729906,
|
"repoId": 190729906,
|
||||||
"pullRequestNo": 1383
|
"pullRequestNo": 1383
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "aptkingston",
|
||||||
|
"id": 9075550,
|
||||||
|
"comment_id": 830252031,
|
||||||
|
"created_at": "2021-04-30T17:37:37Z",
|
||||||
|
"repoId": 190729906,
|
||||||
|
"pullRequestNo": 1431
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "kevmodrome",
|
||||||
|
"id": 534488,
|
||||||
|
"comment_id": 830545461,
|
||||||
|
"created_at": "2021-05-01T05:27:53Z",
|
||||||
|
"repoId": 190729906,
|
||||||
|
"pullRequestNo": 1431
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -3,6 +3,8 @@
|
||||||
"semi": false,
|
"semi": false,
|
||||||
"singleQuote": false,
|
"singleQuote": false,
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"jsxBracketSameLine": false,
|
||||||
"plugins": ["prettier-plugin-svelte"],
|
"plugins": ["prettier-plugin-svelte"],
|
||||||
"svelteSortOrder" : "scripts-markup-styles"
|
"svelteSortOrder" : "options-scripts-markup-styles"
|
||||||
}
|
}
|
|
@ -1,11 +1,7 @@
|
||||||
{
|
{
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"eslint.format.enable": true,
|
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll": true
|
"source.fixAll": true
|
||||||
},
|
},
|
||||||
"[svelte]": {
|
"editor.defaultFormatter": "svelte.svelte-vscode"
|
||||||
"editor.defaultFormatter": "JamesBirtles.svelte-vscode"
|
|
||||||
},
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
||||||
}
|
}
|
||||||
|
|
13
package.json
13
package.json
|
@ -10,11 +10,11 @@
|
||||||
"eslint-plugin-svelte3": "^2.7.3",
|
"eslint-plugin-svelte3": "^2.7.3",
|
||||||
"kill-port": "^1.6.1",
|
"kill-port": "^1.6.1",
|
||||||
"lerna": "3.14.1",
|
"lerna": "3.14.1",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^2.2.1",
|
||||||
"prettier-plugin-svelte": "^1.4.0",
|
"prettier-plugin-svelte": "^2.2.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rollup-plugin-replace": "^2.2.0",
|
"rollup-plugin-replace": "^2.2.0",
|
||||||
"svelte": "^3.30.0"
|
"svelte": "^3.37.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"bootstrap": "lerna link && lerna bootstrap",
|
"bootstrap": "lerna link && lerna bootstrap",
|
||||||
|
@ -38,5 +38,12 @@
|
||||||
"test:e2e:ci": "lerna run cy:ci",
|
"test:e2e:ci": "lerna run cy:ci",
|
||||||
"build:docker": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh && cd -",
|
"build:docker": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh && cd -",
|
||||||
"build:docker:staging": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh staging && cd -"
|
"build:docker:staging": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh staging && cd -"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@spectrum-css/actionbutton": "^1.0.1",
|
||||||
|
"@spectrum-css/actiongroup": "^1.0.1",
|
||||||
|
"@spectrum-css/link": "^3.1.1",
|
||||||
|
"@spectrum-css/menu": "^3.0.1",
|
||||||
|
"@spectrum-css/toast": "^3.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ const getConfigParams = ({ type, group, user }, otherProps = {}) => {
|
||||||
* @param {Object} scopes - the type, group and userID scopes of the configuration.
|
* @param {Object} scopes - the type, group and userID scopes of the configuration.
|
||||||
* @returns The most granular configuration document based on the scope.
|
* @returns The most granular configuration document based on the scope.
|
||||||
*/
|
*/
|
||||||
const determineScopedConfig = async function(db, { type, user, group }) {
|
const determineScopedConfig = async function (db, { type, user, group }) {
|
||||||
const response = await db.allDocs(
|
const response = await db.allDocs(
|
||||||
getConfigParams(
|
getConfigParams(
|
||||||
{ type, user, group },
|
{ type, user, group },
|
||||||
|
|
|
@ -13,6 +13,6 @@ exports.compare = async (data, encrypted) => {
|
||||||
return bcrypt.compare(data, encrypted)
|
return bcrypt.compare(data, encrypted)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.newid = function() {
|
exports.newid = function () {
|
||||||
return v4().replace(/-/g, "")
|
return v4().replace(/-/g, "")
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ async function authenticate(token, tokenSecret, profile, done) {
|
||||||
* from couchDB rather than environment variables, using this factory is necessary for dynamically configuring passport.
|
* from couchDB rather than environment variables, using this factory is necessary for dynamically configuring passport.
|
||||||
* @returns Dynamically configured Passport Google Strategy
|
* @returns Dynamically configured Passport Google Strategy
|
||||||
*/
|
*/
|
||||||
exports.strategyFactory = async function(config) {
|
exports.strategyFactory = async function (config) {
|
||||||
try {
|
try {
|
||||||
const { clientID, clientSecret, callbackURL } = config
|
const { clientID, clientSecret, callbackURL } = config
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,12 @@ const env = require("../../environment")
|
||||||
|
|
||||||
exports.options = {
|
exports.options = {
|
||||||
secretOrKey: env.JWT_SECRET,
|
secretOrKey: env.JWT_SECRET,
|
||||||
jwtFromRequest: function(ctx) {
|
jwtFromRequest: function (ctx) {
|
||||||
return ctx.cookies.get(Cookies.Auth)
|
return ctx.cookies.get(Cookies.Auth)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.authenticate = async function(jwt, done) {
|
exports.authenticate = async function (jwt, done) {
|
||||||
try {
|
try {
|
||||||
return done(null, jwt)
|
return done(null, jwt)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ exports.options = {}
|
||||||
* @param {*} done - callback from passport to return user information and errors
|
* @param {*} done - callback from passport to return user information and errors
|
||||||
* @returns The authenticated user, or errors if they occur
|
* @returns The authenticated user, or errors if they occur
|
||||||
*/
|
*/
|
||||||
exports.authenticate = async function(email, password, done) {
|
exports.authenticate = async function (email, password, done) {
|
||||||
if (!email) return done(null, false, "Email Required.")
|
if (!email) return done(null, false, "Email Required.")
|
||||||
if (!password) return done(null, false, "Password Required.")
|
if (!password) return done(null, false, "Password Required.")
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"name": "@budibase/bbui",
|
"name": "@budibase/bbui",
|
||||||
"description": "A UI solution used in the different Budibase projects.",
|
"description": "A UI solution used in the different Budibase projects.",
|
||||||
"version": "1.58.13",
|
"version": "1.58.13",
|
||||||
|
"license": "AGPL-3.0",
|
||||||
"svelte": "src/index.js",
|
"svelte": "src/index.js",
|
||||||
"module": "dist/bbui.es.js",
|
"module": "dist/bbui.es.js",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
@ -9,31 +10,24 @@
|
||||||
"import": "./dist/bbui.es.js"
|
"import": "./dist/bbui.es.js"
|
||||||
},
|
},
|
||||||
"./package.json": "./package.json",
|
"./package.json": "./package.json",
|
||||||
"./dist/style.css": "./dist/style.css"
|
"./spectrum-icons-rollup.js": "./src/spectrum-icons-rollup.js",
|
||||||
|
"./spectrum-icons-vite.js": "./src/spectrum-icons-vite.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:builder": "vite build",
|
"build": "rollup -c"
|
||||||
"build": "vite build"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-commonjs": "^16.0.0",
|
"@rollup/plugin-commonjs": "^16.0.0",
|
||||||
"@rollup/plugin-json": "^4.1.0",
|
"@rollup/plugin-json": "^4.1.0",
|
||||||
"@rollup/plugin-node-resolve": "^11.0.0",
|
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||||
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.5",
|
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.2",
|
||||||
"nollup": "^0.14.1",
|
"nollup": "^0.14.1",
|
||||||
"postcss": "^8.2.9",
|
"postcss": "^8.2.9",
|
||||||
"rollup": "^2.34.0",
|
"rollup": "^2.45.2",
|
||||||
"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-plugin-postcss": "^4.0.0",
|
"rollup-plugin-postcss": "^4.0.0",
|
||||||
"rollup-plugin-svelte-hot": "^0.11.0",
|
"rollup-plugin-svelte": "^7.1.0",
|
||||||
"semantic-release": "^17.0.8",
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
"svelte": "^3.29.0",
|
"svelte": "^3.37.0"
|
||||||
"svench": "^0.0.10-7",
|
|
||||||
"vite": "^2.1.5"
|
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"svelte"
|
"svelte"
|
||||||
|
@ -43,11 +37,44 @@
|
||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"markdown-it": "^12.0.4",
|
"@adobe/spectrum-css-workflow-icons": "^1.2.1",
|
||||||
"quill": "^1.3.7",
|
"@spectrum-css/actionbutton": "^1.0.1",
|
||||||
"sirv-cli": "^0.4.6",
|
"@spectrum-css/actiongroup": "^1.0.1",
|
||||||
"svelte-flatpickr": "^2.4.0",
|
"@spectrum-css/avatar": "^3.0.2",
|
||||||
"svelte-portal": "^1.0.0",
|
"@spectrum-css/button": "^3.0.1",
|
||||||
"turndown": "^7.0.0"
|
"@spectrum-css/buttongroup": "^3.0.2",
|
||||||
|
"@spectrum-css/checkbox": "^3.0.2",
|
||||||
|
"@spectrum-css/dialog": "^3.0.1",
|
||||||
|
"@spectrum-css/divider": "^1.0.1",
|
||||||
|
"@spectrum-css/dropzone": "^3.0.2",
|
||||||
|
"@spectrum-css/fieldgroup": "^3.0.2",
|
||||||
|
"@spectrum-css/fieldlabel": "^3.0.1",
|
||||||
|
"@spectrum-css/icon": "^3.0.1",
|
||||||
|
"@spectrum-css/illustratedmessage": "^3.0.2",
|
||||||
|
"@spectrum-css/inputgroup": "^3.0.2",
|
||||||
|
"@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/progressbar": "^1.0.2",
|
||||||
|
"@spectrum-css/progresscircle": "^1.0.2",
|
||||||
|
"@spectrum-css/radio": "^3.0.2",
|
||||||
|
"@spectrum-css/search": "^3.0.2",
|
||||||
|
"@spectrum-css/sidenav": "^3.0.2",
|
||||||
|
"@spectrum-css/switch": "^1.0.2",
|
||||||
|
"@spectrum-css/table": "^3.0.1",
|
||||||
|
"@spectrum-css/tabs": "^3.0.1",
|
||||||
|
"@spectrum-css/tags": "^3.0.2",
|
||||||
|
"@spectrum-css/textfield": "^3.0.1",
|
||||||
|
"@spectrum-css/toast": "^3.0.1",
|
||||||
|
"@spectrum-css/treeview": "^3.0.2",
|
||||||
|
"@spectrum-css/typography": "^3.0.1",
|
||||||
|
"@spectrum-css/underlay": "^2.0.9",
|
||||||
|
"@spectrum-css/vars": "^3.0.1",
|
||||||
|
"dayjs": "^1.10.4",
|
||||||
|
"svelte-flatpickr": "^3.1.0",
|
||||||
|
"svelte-portal": "^1.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,140 +1,25 @@
|
||||||
import * as path from "path"
|
import svelte from "rollup-plugin-svelte"
|
||||||
import svelte from "rollup-plugin-svelte-hot"
|
|
||||||
import resolve from "@rollup/plugin-node-resolve"
|
import resolve from "@rollup/plugin-node-resolve"
|
||||||
import commonjs from "@rollup/plugin-commonjs"
|
import commonjs from "@rollup/plugin-commonjs"
|
||||||
import json from "@rollup/plugin-json"
|
import json from "@rollup/plugin-json"
|
||||||
import copy from "rollup-plugin-copy"
|
import { terser } from "rollup-plugin-terser"
|
||||||
import hmr from "rollup-plugin-hot"
|
|
||||||
import del from "rollup-plugin-delete"
|
|
||||||
import postcss from "rollup-plugin-postcss"
|
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
|
export default {
|
||||||
const SVENCH = !!process.env.SVENCH
|
input: "src/index.js",
|
||||||
const HOT = WATCH
|
output: {
|
||||||
const PRODUCTION = !WATCH
|
sourcemap: true,
|
||||||
|
format: "esm",
|
||||||
const svench = Svench({
|
file: "dist/bbui.es.js",
|
||||||
// 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",
|
|
||||||
},
|
},
|
||||||
|
plugins: [
|
||||||
extensions: [".svench", ".svench.svelte", ".svench.svx", ".md"],
|
resolve(),
|
||||||
|
commonjs(),
|
||||||
serve: WATCH && {
|
svelte({
|
||||||
host: "0.0.0.0",
|
emitCss: true,
|
||||||
port: 4242,
|
}),
|
||||||
public: "public",
|
postcss(),
|
||||||
nollup: "0.0.0.0:42421",
|
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"]()
|
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/actionbutton/dist/index-vars.css"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
export let quiet = false
|
||||||
|
export let emphasized = false
|
||||||
|
export let selected = false
|
||||||
|
export let longPressable = false
|
||||||
|
export let disabled = false
|
||||||
|
export let icon = ""
|
||||||
|
export let dataCy = null
|
||||||
|
export let size = "M"
|
||||||
|
|
||||||
|
function longPress(element) {
|
||||||
|
if (!longPressable) return
|
||||||
|
let timer
|
||||||
|
|
||||||
|
const listener = () => {
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
dispatch("longpress")
|
||||||
|
}, 700)
|
||||||
|
}
|
||||||
|
|
||||||
|
element.addEventListener("pointerdown", listener)
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
clearTimeout(timer)
|
||||||
|
element.removeEventListener("pointerdown", longPress)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button
|
||||||
|
data-cy={dataCy}
|
||||||
|
use:longPress
|
||||||
|
class:spectrum-ActionButton--quiet={quiet}
|
||||||
|
class:spectrum-ActionButton--emphasized={emphasized}
|
||||||
|
class:is-selected={selected}
|
||||||
|
class="spectrum-ActionButton spectrum-ActionButton--size{size}"
|
||||||
|
{disabled}
|
||||||
|
on:longPress
|
||||||
|
on:click|preventDefault
|
||||||
|
>
|
||||||
|
{#if longPressable}
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-UIIcon-CornerTriangle100 spectrum-ActionButton-hold"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-css-icon-CornerTriangle100" />
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
{#if icon}
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-Icon--size{size}"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
aria-label={icon}
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
{#if $$slots}
|
||||||
|
<span class="spectrum-ActionButton-label"><slot /></span>
|
||||||
|
{/if}
|
||||||
|
</button>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/actiongroup/dist/index-vars.css"
|
||||||
|
export let vertical = false
|
||||||
|
export let justified = false
|
||||||
|
export let quiet = false
|
||||||
|
export let compact = false
|
||||||
|
|
||||||
|
// Attaches a spectrum-ActionGroup-item class to buttons inside the div
|
||||||
|
function group(element) {
|
||||||
|
const buttons = Array.from(element.getElementsByTagName("button"))
|
||||||
|
buttons.forEach(button => {
|
||||||
|
button.classList.add("spectrum-ActionGroup-item")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
use:group
|
||||||
|
class:spectrum-ActionGroup--vertical={vertical}
|
||||||
|
class:spectrum-ActionGroup--justified={justified}
|
||||||
|
class:spectrum-ActionGroup--quiet={quiet}
|
||||||
|
class:spectrum-ActionGroup--compact={compact}
|
||||||
|
class="spectrum-ActionGroup"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<script>
|
||||||
|
import { setContext } from "svelte"
|
||||||
|
import Popover from "../Popover/Popover.svelte"
|
||||||
|
import Menu from "../Menu/Menu.svelte"
|
||||||
|
|
||||||
|
export let disabled = false
|
||||||
|
|
||||||
|
let anchor
|
||||||
|
let dropdown
|
||||||
|
|
||||||
|
// This is needed because display: contents is considered "invisible".
|
||||||
|
// It should only ever be an action button, so should be fine.
|
||||||
|
function getAnchor(node) {
|
||||||
|
anchor = node.firstChild
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hide = () => {
|
||||||
|
dropdown.hide()
|
||||||
|
}
|
||||||
|
export const show = () => {
|
||||||
|
dropdown.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
const openMenu = () => {
|
||||||
|
if (!disabled) show()
|
||||||
|
}
|
||||||
|
|
||||||
|
setContext("actionMenu", { show, hide })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div use:getAnchor on:click={openMenu}>
|
||||||
|
<slot name="control" />
|
||||||
|
</div>
|
||||||
|
<Popover bind:this={dropdown} {anchor} align="left">
|
||||||
|
<Menu>
|
||||||
|
<slot />
|
||||||
|
</Menu>
|
||||||
|
</Popover>
|
|
@ -5,14 +5,14 @@ export default function clickOutside(element, callbackFunction) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.addEventListener("click", onClick, true)
|
document.body.addEventListener("mousedown", onClick, true)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
update(newCallbackFunction) {
|
update(newCallbackFunction) {
|
||||||
callbackFunction = newCallbackFunction
|
callbackFunction = newCallbackFunction
|
||||||
},
|
},
|
||||||
destroy() {
|
destroy() {
|
||||||
document.body.removeEventListener("click", onClick, true)
|
document.body.removeEventListener("mousedown", onClick, true)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,10 @@ export default function positionDropdown(element, { anchor, align }) {
|
||||||
if (spaceAbove > spaceBelow) {
|
if (spaceAbove > spaceBelow) {
|
||||||
positionSide = "bottom"
|
positionSide = "bottom"
|
||||||
maxHeight = spaceAbove - 20
|
maxHeight = spaceAbove - 20
|
||||||
y = window.innerHeight - spaceAbove
|
y = window.innerHeight - spaceAbove + 5
|
||||||
} else {
|
} else {
|
||||||
positionSide = "top"
|
positionSide = "top"
|
||||||
y = bottom
|
y = bottom + 5
|
||||||
maxHeight = spaceBelow - 20
|
maxHeight = spaceBelow - 20
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/avatar/dist/index-vars.css"
|
||||||
|
export let url = ""
|
||||||
|
export let disabled = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<img
|
||||||
|
class:is-disabled={disabled}
|
||||||
|
class="spectrum-Avatar"
|
||||||
|
src={url}
|
||||||
|
alt="Avatar"
|
||||||
|
/>
|
|
@ -1,212 +1,52 @@
|
||||||
<script>
|
<script>
|
||||||
export let primary = false,
|
import "@spectrum-css/button/dist/index-vars.css"
|
||||||
secondary = false,
|
|
||||||
blue = false,
|
export let disabled = false
|
||||||
disabled = false,
|
export let size = "M"
|
||||||
translucent = false,
|
export let cta = false
|
||||||
text = false,
|
export let primary = false
|
||||||
red = false,
|
export let secondary = false
|
||||||
yellow = false,
|
export let warning = false
|
||||||
orange = false,
|
export let overBackground = false
|
||||||
green = false,
|
export let quiet = false
|
||||||
purple = false,
|
export let icon = undefined
|
||||||
small = false,
|
export let active = false
|
||||||
medium = false,
|
|
||||||
wide = false,
|
|
||||||
large = false,
|
|
||||||
href = false
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if href}
|
<button
|
||||||
<a
|
class:spectrum-Button--cta={cta}
|
||||||
{href}
|
class:spectrum-Button--primary={primary}
|
||||||
class:primary
|
class:spectrum-Button--secondary={secondary}
|
||||||
class:secondary
|
class:spectrum-Button--warning={warning}
|
||||||
class:translucent
|
class:spectrum-Button--overBackground={overBackground}
|
||||||
class:blue
|
class:spectrum-Button--quiet={quiet}
|
||||||
class:red
|
class:active
|
||||||
class:yellow
|
class="spectrum-Button spectrum-Button--size{size.toUpperCase()}"
|
||||||
class:orange
|
{disabled}
|
||||||
class:green
|
on:click|preventDefault
|
||||||
class:purple
|
>
|
||||||
class:small
|
{#if icon}
|
||||||
class:medium
|
<svg
|
||||||
class:wide
|
class="spectrum-Icon spectrum-Icon--size{size.toUpperCase()}"
|
||||||
class:large
|
focusable="false"
|
||||||
class:text
|
aria-hidden="true"
|
||||||
{disabled}>
|
aria-label={icon}
|
||||||
<slot />
|
>
|
||||||
</a>
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
{:else}
|
</svg>
|
||||||
<button
|
{/if}
|
||||||
class:primary
|
{#if $$slots}
|
||||||
class:secondary
|
<span class="spectrum-Button-label"><slot /></span>
|
||||||
class:translucent
|
{/if}
|
||||||
class:blue
|
</button>
|
||||||
class:red
|
|
||||||
class:yellow
|
|
||||||
class:orange
|
|
||||||
class:green
|
|
||||||
class:purple
|
|
||||||
class:small
|
|
||||||
class:medium
|
|
||||||
class:wide
|
|
||||||
class:large
|
|
||||||
class:text
|
|
||||||
{disabled}
|
|
||||||
on:click|preventDefault>
|
|
||||||
<slot />
|
|
||||||
</button>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
button,
|
.spectrum-Button-label {
|
||||||
a {
|
white-space: nowrap;
|
||||||
font-family: var(--font-sans);
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 600;
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: var(--border-radius-s);
|
text-overflow: ellipsis;
|
||||||
color: white;
|
|
||||||
padding: var(--spacing-s) var(--spacing-l);
|
|
||||||
transition: all 0.2s ease 0s;
|
|
||||||
display: inline-flex;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
text-decoration: none;
|
|
||||||
min-width: auto;
|
|
||||||
outline: none;
|
|
||||||
font-feature-settings: "case" 1, "rlig" 1, "calt" 0;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
user-select: none;
|
|
||||||
flex-shrink: 0;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 0;
|
|
||||||
border-width: 2px;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
}
|
||||||
|
.active {
|
||||||
.primary {
|
color: var(--spectrum-global-color-blue-600) !important;
|
||||||
color: var(--background);
|
|
||||||
border-color: var(--ink);
|
|
||||||
background-color: var(--ink);
|
|
||||||
}
|
|
||||||
button.primary:hover:not([disabled]) {
|
|
||||||
background-color: var(--background);
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
.secondary {
|
|
||||||
border-color: var(--grey-4);
|
|
||||||
background-color: var(--background);
|
|
||||||
color: var(--grey-8);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
button.secondary:hover:not([disabled]) {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
.translucent {
|
|
||||||
border-color: rgba(0, 0, 0, 0.1);
|
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
|
||||||
color: var(--grey-6);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
button.translucent:hover:not([disabled]) {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
.blue {
|
|
||||||
background-color: var(--blue);
|
|
||||||
border-color: var(--blue);
|
|
||||||
}
|
|
||||||
button.blue:hover:not([disabled]) {
|
|
||||||
background-color: var(--blue-light);
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
.red {
|
|
||||||
border-color: var(--red);
|
|
||||||
background-color: var(--red);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
button.red:hover:not([disabled]) {
|
|
||||||
background-color: var(--red-light);
|
|
||||||
color: var(--red);
|
|
||||||
}
|
|
||||||
.yellow {
|
|
||||||
border-color: var(--yellow);
|
|
||||||
background-color: var(--yellow);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
button.yellow:hover:not([disabled]) {
|
|
||||||
background-color: var(--yellow-light);
|
|
||||||
color: var(--yellow);
|
|
||||||
}
|
|
||||||
.orange {
|
|
||||||
border-color: var(--orange);
|
|
||||||
background-color: var(--orange);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
button.orange:hover:not([disabled]) {
|
|
||||||
background-color: var(--orange-light);
|
|
||||||
color: var(--orange);
|
|
||||||
}
|
|
||||||
.green {
|
|
||||||
border-color: var(--green);
|
|
||||||
background-color: var(--green);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
button.green:hover:not([disabled]) {
|
|
||||||
background-color: var(--green-light);
|
|
||||||
color: var(--green);
|
|
||||||
}
|
|
||||||
.purple {
|
|
||||||
border-color: var(--purple);
|
|
||||||
background-color: var(--purple);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
button.purple:hover:not([disabled]) {
|
|
||||||
background-color: var(--purple-light);
|
|
||||||
color: var(--purple);
|
|
||||||
}
|
|
||||||
.text {
|
|
||||||
background-color: transparent;
|
|
||||||
color: var(--grey-7);
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
button.text:hover:not([disabled]) {
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
button.text:active:not([disabled]) {
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
.small {
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
padding: var(--spacing-xs) var(--spacing-m);
|
|
||||||
}
|
|
||||||
|
|
||||||
.medium {
|
|
||||||
font-size: var(--font-size-m);
|
|
||||||
padding: var(--spacing-s) var(--spacing-l);
|
|
||||||
}
|
|
||||||
|
|
||||||
.large {
|
|
||||||
font-size: var(--font-size-l);
|
|
||||||
padding: var(--spacing-m) var(--layout-l);
|
|
||||||
}
|
|
||||||
.wide {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:disabled {
|
|
||||||
background-color: var(--grey-4);
|
|
||||||
cursor: not-allowed;
|
|
||||||
border-color: var(--grey-4);
|
|
||||||
color: var(--grey-5);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
<script>
|
|
||||||
export let onClose
|
|
||||||
export let dark = false
|
|
||||||
export let small = false
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<button class:small class:dark on:click={onClose}>×</button>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
button {
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: absolute;
|
|
||||||
font-size: var(--font-size-l);
|
|
||||||
z-index: 1000;
|
|
||||||
top: var(--spacing-l);
|
|
||||||
right: var(--spacing-l);
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
width: 1.5rem;
|
|
||||||
height: 1.5rem;
|
|
||||||
border: 0;
|
|
||||||
color: black;
|
|
||||||
border-radius: var(--border-radius-xl);
|
|
||||||
background: white;
|
|
||||||
transition: transform 0.2s cubic-bezier(0.25, 0.1, 0.25, 1),
|
|
||||||
background 0.2s cubic-bezier(0.25, 0.1, 0.25, 1);
|
|
||||||
-webkit-appearance: none;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:active {
|
|
||||||
background-color: var(--grey-4);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.small {
|
|
||||||
font-size: var(--font-size-m);
|
|
||||||
line-height: 110%;
|
|
||||||
width: 1.3rem;
|
|
||||||
height: 1.3rem;
|
|
||||||
}
|
|
||||||
.dark {
|
|
||||||
color: white;
|
|
||||||
background: black;
|
|
||||||
}
|
|
||||||
.dark:hover {
|
|
||||||
background-color: var(--grey-8);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.dark:active {
|
|
||||||
background-color: var(--grey-9);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,36 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Close from "./Close.svelte";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
div {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
min-width: 400px;
|
|
||||||
height: 200px;
|
|
||||||
border: var(--border-dark);
|
|
||||||
border-radius: var(--border-radius-l);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<div>
|
|
||||||
<Close />
|
|
||||||
</div>
|
|
||||||
</View>
|
|
||||||
<View name="dark color">
|
|
||||||
<div>
|
|
||||||
<Close dark />
|
|
||||||
</div>
|
|
||||||
</View>
|
|
||||||
<View name="small">
|
|
||||||
<div>
|
|
||||||
<Close small />
|
|
||||||
</div>
|
|
||||||
</View>
|
|
||||||
<View name="small dark">
|
|
||||||
<div>
|
|
||||||
<Close small dark />
|
|
||||||
</div>
|
|
||||||
</View>
|
|
|
@ -1,128 +0,0 @@
|
||||||
<script>
|
|
||||||
export let active = false,
|
|
||||||
text = false,
|
|
||||||
small = false,
|
|
||||||
medium = false,
|
|
||||||
large = false,
|
|
||||||
blue = false,
|
|
||||||
green = false,
|
|
||||||
yellow = false,
|
|
||||||
purple = false,
|
|
||||||
red = false,
|
|
||||||
orange = false,
|
|
||||||
disabled = false,
|
|
||||||
href = false
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if href}
|
|
||||||
<a
|
|
||||||
{href}
|
|
||||||
class:active
|
|
||||||
class:small
|
|
||||||
class:medium
|
|
||||||
class:large
|
|
||||||
class:text
|
|
||||||
class:blue
|
|
||||||
class:green
|
|
||||||
class:yellow
|
|
||||||
class:purple
|
|
||||||
class:red
|
|
||||||
class:orange><slot /></a>
|
|
||||||
{:else}
|
|
||||||
<button
|
|
||||||
class:active
|
|
||||||
class:small
|
|
||||||
class:medium
|
|
||||||
class:large
|
|
||||||
class:text
|
|
||||||
class:blue
|
|
||||||
class:green
|
|
||||||
class:yellow
|
|
||||||
class:purple
|
|
||||||
class:red
|
|
||||||
class:orange
|
|
||||||
{disabled}
|
|
||||||
on:click|preventDefault>
|
|
||||||
<slot />
|
|
||||||
</button>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
button,
|
|
||||||
a {
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 600;
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow: hidden;
|
|
||||||
transition: all 0.08s ease 0s;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
text-decoration: none;
|
|
||||||
outline: none;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
user-select: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
background-color: transparent;
|
|
||||||
color: var(--grey-7);
|
|
||||||
border: none;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
button.text:hover:not([disabled]) {
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
button.text:active:not([disabled]) {
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
button.text.active:not([disabled]) {
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
button.text:disabled {
|
|
||||||
cursor: not-allowed;
|
|
||||||
color: var(--grey-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.blue {
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
.green {
|
|
||||||
color: var(--green);
|
|
||||||
}
|
|
||||||
|
|
||||||
.red {
|
|
||||||
color: var(--red);
|
|
||||||
}
|
|
||||||
|
|
||||||
.purple {
|
|
||||||
color: var(--purple);
|
|
||||||
}
|
|
||||||
|
|
||||||
.yellow {
|
|
||||||
color: var(--yellow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.orange {
|
|
||||||
color: var(--orange);
|
|
||||||
}
|
|
||||||
|
|
||||||
.small {
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.medium {
|
|
||||||
font-size: var(--font-size-s);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.large {
|
|
||||||
font-size: var(--font-size-m);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,69 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import TextButton from "./TextButton.svelte";
|
|
||||||
import Icon from "../Icons/Icon.svelte";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
div {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
|
||||||
gap: var(--spacing-xl);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<View name="Text">
|
|
||||||
<div>
|
|
||||||
<TextButton text small on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="view" />
|
|
||||||
Add View
|
|
||||||
</TextButton>
|
|
||||||
<TextButton text medium on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="addcolumn" />
|
|
||||||
Add Column
|
|
||||||
</TextButton>
|
|
||||||
<TextButton text large on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="addrow" />
|
|
||||||
Add Row
|
|
||||||
</TextButton>
|
|
||||||
<TextButton text disabled on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="arrow" direction="w" />
|
|
||||||
Disabled Text Button
|
|
||||||
</TextButton>
|
|
||||||
<TextButton active text on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="calculate" />
|
|
||||||
Active Calculation
|
|
||||||
</TextButton>
|
|
||||||
</div>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Colours">
|
|
||||||
<div>
|
|
||||||
<TextButton text medium yellow on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="view" />
|
|
||||||
Add View
|
|
||||||
</TextButton>
|
|
||||||
<TextButton text medium blue on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="addcolumn" />
|
|
||||||
Add Column
|
|
||||||
</TextButton>
|
|
||||||
<TextButton text medium purple on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="addrow" />
|
|
||||||
Add Row
|
|
||||||
</TextButton>
|
|
||||||
<TextButton text medium red on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="arrow" />
|
|
||||||
Delete
|
|
||||||
</TextButton>
|
|
||||||
<TextButton text medium green on:click={() => alert('Clicked!')}>
|
|
||||||
<Icon name="calculate" />
|
|
||||||
Calculate
|
|
||||||
</TextButton>
|
|
||||||
</div>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Usage as a link">
|
|
||||||
<div>
|
|
||||||
<TextButton green text href="https://google.com">This is a link</TextButton>
|
|
||||||
</div>
|
|
||||||
</View>
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/buttongroup/dist/index-vars.css"
|
||||||
|
export let vertical = false
|
||||||
|
|
||||||
|
function group(element) {
|
||||||
|
const buttons = Array.from(element.getElementsByTagName("button"))
|
||||||
|
buttons.forEach(button => {
|
||||||
|
button.classList.add("spectrum-ButtonGroup-item")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
use:group
|
||||||
|
class="spectrum-ButtonGroup"
|
||||||
|
class:spectrum-ButtonGroup--vertical={vertical}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script>
|
||||||
|
export let small = false
|
||||||
|
export let disabled
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button
|
||||||
|
on:click
|
||||||
|
class="spectrum-ClearButton"
|
||||||
|
class:spectrum-ClearButton--small={small}
|
||||||
|
{disabled}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-UIIcon-Cross75"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-css-icon-Cross75" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
|
@ -1,45 +0,0 @@
|
||||||
<script>
|
|
||||||
import Flatpickr from "svelte-flatpickr"
|
|
||||||
import { Label, Input } from "../"
|
|
||||||
import "flatpickr/dist/flatpickr.css"
|
|
||||||
|
|
||||||
const PICKER_OPTIONS = {
|
|
||||||
enableTime: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
export let label
|
|
||||||
export let placeholder
|
|
||||||
export let value
|
|
||||||
export let thin = false
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class:thin>
|
|
||||||
{#if label}
|
|
||||||
<Label extraSmall grey>{label}</Label>
|
|
||||||
{/if}
|
|
||||||
<Flatpickr {placeholder} options={PICKER_OPTIONS} on:change bind:value />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
:global(.flatpickr-input) {
|
|
||||||
width: 100%;
|
|
||||||
min-width: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: var(--ink);
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
padding: var(--spacing-m);
|
|
||||||
font-size: var(--font-size-s);
|
|
||||||
margin: 0;
|
|
||||||
outline: none;
|
|
||||||
border: var(--border-transparent);
|
|
||||||
}
|
|
||||||
:global(.flatpickr-input:focus) {
|
|
||||||
border: var(--border-blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
div.thin :global(.flatpickr-input) {
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,17 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import DatePicker from "./DatePicker.svelte";
|
|
||||||
|
|
||||||
function handleChange(event) {
|
|
||||||
const [fullDate, shortDate, instance] = event.detail
|
|
||||||
alert("Date is " + fullDate)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<DatePicker on:change={handleChange} label="Start Date" placeholder="Pick a date" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="thin">
|
|
||||||
<DatePicker on:change={handleChange} label="Start Date" thin placeholder="Pick a date" />
|
|
||||||
</View>
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
|
import Icon from "../Icon/Icon.svelte"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
@ -7,8 +8,6 @@
|
||||||
export let name,
|
export let name,
|
||||||
show = false
|
show = false
|
||||||
|
|
||||||
const capitalize = name => name[0].toUpperCase() + name.slice(1)
|
|
||||||
|
|
||||||
const onHeaderClick = () => {
|
const onHeaderClick = () => {
|
||||||
show = !show
|
show = !show
|
||||||
if (show) {
|
if (show) {
|
||||||
|
@ -19,9 +18,9 @@
|
||||||
|
|
||||||
<div class="property-group-container" class:thin>
|
<div class="property-group-container" class:thin>
|
||||||
<div class="property-group-name" on:click={onHeaderClick}>
|
<div class="property-group-name" on:click={onHeaderClick}>
|
||||||
<div class:thin class="name">{capitalize(name)}</div>
|
<div class:thin class="name">{name}</div>
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<i class={show ? 'ri-arrow-down-s-fill' : 'ri-arrow-left-s-fill'} />
|
<Icon size="S" name={show ? "Remove" : "Add"} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="property-panel" class:show>
|
<div class="property-panel" class:show>
|
||||||
|
@ -57,10 +56,12 @@
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
text-transform: capitalize;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
.name.thin {
|
.name.thin {
|
||||||
font-size: var(--font-size-xs);
|
font-size: var(--spectrum-global-dimension-font-size-75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
|
@ -0,0 +1,25 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/divider/dist/index-vars.css"
|
||||||
|
export let size = "M"
|
||||||
|
|
||||||
|
export let vertical = false
|
||||||
|
export let noMargin = false
|
||||||
|
export let noGrid = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<hr
|
||||||
|
class:noMargin
|
||||||
|
class:noGrid
|
||||||
|
class="spectrum-Divider spectrum-Divider--{vertical
|
||||||
|
? 'vertical'
|
||||||
|
: 'horizontal'} spectrum-Dialog-divider spectrum-Divider--size{size}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
hr.noMargin {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
hr.noGrid {
|
||||||
|
grid-area: auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,7 +1,9 @@
|
||||||
<script>
|
<script>
|
||||||
import { slide } from "svelte/transition"
|
import { slide } from "svelte/transition"
|
||||||
import Portal from "svelte-portal"
|
import Portal from "svelte-portal"
|
||||||
import clickOutside from "../Actions/click_outside"
|
import ActionButton from "../ActionButton/ActionButton.svelte"
|
||||||
|
import Body from "../Typography/Body.svelte"
|
||||||
|
import Heading from "../Typography/Heading.svelte"
|
||||||
|
|
||||||
export let title
|
export let title
|
||||||
|
|
||||||
|
@ -35,12 +37,14 @@
|
||||||
<section class="drawer" transition:slide>
|
<section class="drawer" transition:slide>
|
||||||
<header>
|
<header>
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<div class="title">{title}</div>
|
<Heading size="XS">{title}</Heading>
|
||||||
<slot name="description" />
|
<Body size="XXS">
|
||||||
|
<slot name="description" />
|
||||||
|
</Body>
|
||||||
</div>
|
</div>
|
||||||
<div class="controls">
|
<div class="buttons">
|
||||||
<slot name="buttons" />
|
<slot name="buttons" />
|
||||||
<i class="ri-close-fill close" on:click={hide} />
|
<ActionButton quiet icon="Close" on:click={hide} />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<slot name="body" />
|
<slot name="body" />
|
||||||
|
@ -64,25 +68,17 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: var(--border-light);
|
border-bottom: var(--border-light);
|
||||||
padding: var(--spacing-m);
|
padding: var(--spectrum-alias-item-padding-s) 0;
|
||||||
|
}
|
||||||
|
header :global(*) + :global(*) {
|
||||||
|
margin: 0 var(--spectrum-alias-grid-baseline);
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls {
|
|
||||||
display: grid;
|
|
||||||
grid-auto-flow: column;
|
|
||||||
grid-gap: var(--spacing-m);
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
font-size: var(--font-size-xl);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.title {
|
|
||||||
font-weight: bold;
|
|
||||||
margin-right: var(--spacing-m);
|
|
||||||
}
|
|
||||||
.text {
|
.text {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: var(--spectrum-alias-item-padding-s);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<div class="drawer-contents">
|
||||||
|
<div class:no-sidebar={!$$slots.sidebar} class="container">
|
||||||
|
{#if $$slots.sidebar}
|
||||||
|
<div class="sidebar">
|
||||||
|
<slot name="sidebar" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="main">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.drawer-contents {
|
||||||
|
height: 40vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
height: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 290px 1fr;
|
||||||
|
}
|
||||||
|
.no-sidebar {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
.sidebar {
|
||||||
|
border-right: var(--border-light);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.sidebar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.main {
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
}
|
||||||
|
.main :global(textarea) {
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
.main :global(p) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,77 +0,0 @@
|
||||||
<script>
|
|
||||||
import Portal from "svelte-portal"
|
|
||||||
import { createEventDispatcher } from "svelte"
|
|
||||||
import buildStyle from "../utils/buildStyle"
|
|
||||||
import positionDropdown from "../Actions/position_dropdown"
|
|
||||||
import clickOutside from "../Actions/click_outside"
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
export let anchor
|
|
||||||
export let align = "right"
|
|
||||||
export let borderColor = ""
|
|
||||||
|
|
||||||
export const show = () => {
|
|
||||||
dispatch("open")
|
|
||||||
open = true
|
|
||||||
}
|
|
||||||
|
|
||||||
export const hide = () => {
|
|
||||||
dispatch("close")
|
|
||||||
open = false
|
|
||||||
}
|
|
||||||
|
|
||||||
let open = null
|
|
||||||
|
|
||||||
function handleEscape(e) {
|
|
||||||
if (open && e.key === "Escape") {
|
|
||||||
hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$: menuStyle = buildStyle({
|
|
||||||
borderColor,
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if open}
|
|
||||||
<Portal>
|
|
||||||
<div
|
|
||||||
tabindex="0"
|
|
||||||
class:open
|
|
||||||
use:positionDropdown={{ anchor, align }}
|
|
||||||
use:clickOutside={hide}
|
|
||||||
style={menuStyle}
|
|
||||||
on:keydown={handleEscape}
|
|
||||||
class="menu-container">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</Portal>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.menu-container {
|
|
||||||
position: fixed;
|
|
||||||
margin-top: var(--spacing-xs);
|
|
||||||
outline: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
opacity: 0;
|
|
||||||
min-width: 200px;
|
|
||||||
z-index: 2;
|
|
||||||
color: var(--ink);
|
|
||||||
font-weight: 400;
|
|
||||||
height: fit-content !important;
|
|
||||||
border: var(--border-dark);
|
|
||||||
border-radius: var(--border-radius-m);
|
|
||||||
transform: scale(0);
|
|
||||||
transition: opacity 0.13s linear, transform 0.12s cubic-bezier(0, 0, 0.2, 1);
|
|
||||||
overflow-y: auto;
|
|
||||||
background: var(--background);
|
|
||||||
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.open {
|
|
||||||
transform: scale(1);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,161 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import DropdownMenu from "./DropdownMenu.svelte";
|
|
||||||
import Button from "../Button/Button.svelte";
|
|
||||||
import Icon from "../Icons/Icon.svelte";
|
|
||||||
|
|
||||||
let anchorRight;
|
|
||||||
let anchorLeft;
|
|
||||||
let dropdownRight;
|
|
||||||
let dropdownLeft;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
ul {
|
|
||||||
list-style: none;
|
|
||||||
padding-left: 0;
|
|
||||||
margin: 0;
|
|
||||||
padding: var(--spacing-s) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
display: flex;
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
color: var(--ink);
|
|
||||||
padding: var(--spacing-s) var(--spacing-m);
|
|
||||||
margin: auto 0px;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
li:hover {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
li:active {
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<View name="Right Align (default)">
|
|
||||||
<div bind:this={anchorRight}>
|
|
||||||
<Button primary on:click={dropdownRight.show}>Right Align</Button>
|
|
||||||
</div>
|
|
||||||
<DropdownMenu bind:this={dropdownRight} anchor={anchorRight}>
|
|
||||||
<ul>
|
|
||||||
<li>Item 1</li>
|
|
||||||
<li>Item 2</li>
|
|
||||||
<li>Item 3</li>
|
|
||||||
</ul>
|
|
||||||
</DropdownMenu>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Left Align">
|
|
||||||
<div bind:this={anchorLeft}>
|
|
||||||
<Button primary on:click={dropdownLeft.show}>Left Align</Button>
|
|
||||||
</div>
|
|
||||||
<DropdownMenu bind:this={dropdownLeft} anchor={anchorLeft} align="left">
|
|
||||||
<ul>
|
|
||||||
<li>Item 1</li>
|
|
||||||
<li>Item 2</li>
|
|
||||||
<li>Item 3</li>
|
|
||||||
</ul>
|
|
||||||
</DropdownMenu>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Left Align, TextButton, Small, Icons">
|
|
||||||
<div bind:this={anchorLeft}>
|
|
||||||
<Button text on:click={dropdownLeft.show}>
|
|
||||||
Field Name
|
|
||||||
<Icon name="arrowdown" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<DropdownMenu bind:this={dropdownLeft} anchor={anchorLeft} align="left">
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<Icon name="edit" />
|
|
||||||
Edit
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Icon name="delete" />
|
|
||||||
Delete
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Icon name="sortascending" />
|
|
||||||
Sort A - Z
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Icon name="sortdescending" />
|
|
||||||
Sort Z - A
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</DropdownMenu>
|
|
||||||
</View>
|
|
||||||
<View name="Dropdown menu with slim menu and border color">
|
|
||||||
<div bind:this={anchorLeft}>
|
|
||||||
<Button primary on:click={dropdownLeft.show}>
|
|
||||||
Field Name
|
|
||||||
<Icon name="arrowdown" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<DropdownMenu
|
|
||||||
bind:this={dropdownLeft}
|
|
||||||
width="175px"
|
|
||||||
borderColor="#d1d1d1ff"
|
|
||||||
anchor={anchorLeft}
|
|
||||||
align="left">
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<Icon name="edit" />
|
|
||||||
Edit
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Icon name="delete" />
|
|
||||||
Delete
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Icon name="sortascending" />
|
|
||||||
Sort A - Z
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Icon name="sortdescending" />
|
|
||||||
Sort Z - A
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</DropdownMenu>
|
|
||||||
</View>
|
|
||||||
<View name="Dropdown on close event example">
|
|
||||||
<div bind:this={anchorLeft}>
|
|
||||||
<Button primary on:click={dropdownLeft.show}>
|
|
||||||
Field Name
|
|
||||||
<Icon name="arrowdown" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<DropdownMenu
|
|
||||||
on:close={() => alert('Closed!')}
|
|
||||||
bind:this={dropdownLeft}
|
|
||||||
width="175px"
|
|
||||||
borderColor="#d1d1d1ff"
|
|
||||||
anchor={anchorLeft}
|
|
||||||
align="left">
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<Icon name="edit" />
|
|
||||||
Edit
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Icon name="delete" />
|
|
||||||
Delete
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Icon name="sortascending" />
|
|
||||||
Sort A - Z
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Icon name="sortdescending" />
|
|
||||||
Sort Z - A
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</DropdownMenu>
|
|
||||||
</View>
|
|
|
@ -1,295 +0,0 @@
|
||||||
<script>
|
|
||||||
import { Heading, Body, Button } from "../"
|
|
||||||
import { FILE_TYPES } from "./fileTypes"
|
|
||||||
|
|
||||||
const BYTES_IN_KB = 1000
|
|
||||||
const BYTES_IN_MB = 1000000
|
|
||||||
|
|
||||||
export let icons = {
|
|
||||||
image: "fas fa-file-image",
|
|
||||||
code: "fas fa-file-code",
|
|
||||||
file: "fas fa-file",
|
|
||||||
fileUpload: "fas fa-upload",
|
|
||||||
}
|
|
||||||
|
|
||||||
export let files = []
|
|
||||||
export let fileSizeLimit = BYTES_IN_MB * 20
|
|
||||||
export let processFiles
|
|
||||||
export let handleFileTooLarge
|
|
||||||
|
|
||||||
let selectedImageIdx = 0
|
|
||||||
let fileDragged = false
|
|
||||||
// Generate a random ID so that multiple dropzones on the page don't conflict
|
|
||||||
let id = Math.random()
|
|
||||||
.toString(36)
|
|
||||||
.substring(7)
|
|
||||||
|
|
||||||
$: selectedImage = files ? files[selectedImageIdx] : null
|
|
||||||
|
|
||||||
function determineFileIcon(extension) {
|
|
||||||
const ext = extension.toLowerCase()
|
|
||||||
|
|
||||||
if (FILE_TYPES.IMAGE.includes(ext)) return icons.image
|
|
||||||
if (FILE_TYPES.CODE.includes(ext)) return icons.code
|
|
||||||
|
|
||||||
return icons.file
|
|
||||||
}
|
|
||||||
|
|
||||||
async function processFileList(fileList) {
|
|
||||||
if (Array.from(fileList).some(file => file.size >= fileSizeLimit)) {
|
|
||||||
handleFileTooLarge(fileSizeLimit, file)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const processedFiles = await processFiles(fileList)
|
|
||||||
|
|
||||||
files = [...processedFiles, ...files]
|
|
||||||
selectedImageIdx = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removeFile() {
|
|
||||||
files.splice(selectedImageIdx, 1)
|
|
||||||
files = files
|
|
||||||
selectedImageIdx = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigateLeft() {
|
|
||||||
selectedImageIdx -= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigateRight() {
|
|
||||||
selectedImageIdx += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFile(evt) {
|
|
||||||
processFileList(evt.target.files)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDragOver(evt) {
|
|
||||||
evt.preventDefault()
|
|
||||||
fileDragged = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDragLeave(evt) {
|
|
||||||
evt.preventDefault()
|
|
||||||
fileDragged = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDrop(evt) {
|
|
||||||
evt.preventDefault()
|
|
||||||
processFileList(evt.dataTransfer.files)
|
|
||||||
fileDragged = false
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="dropzone"
|
|
||||||
on:dragover={handleDragOver}
|
|
||||||
on:dragleave={handleDragLeave}
|
|
||||||
on:dragenter={handleDragOver}
|
|
||||||
on:drop={handleDrop}
|
|
||||||
class:fileDragged>
|
|
||||||
{#if selectedImage}
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<header>
|
|
||||||
<div>
|
|
||||||
<i class={determineFileIcon(selectedImage.extension)} />
|
|
||||||
<span class="filename">{selectedImage.name}</span>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
{#if selectedImage.size <= BYTES_IN_MB}
|
|
||||||
{selectedImage.size / BYTES_IN_KB}KB
|
|
||||||
{:else}{selectedImage.size / BYTES_IN_MB}MB{/if}
|
|
||||||
</p>
|
|
||||||
</header>
|
|
||||||
<div class="delete-button" on:click={removeFile}>
|
|
||||||
<i class="ri-close-circle-fill" />
|
|
||||||
</div>
|
|
||||||
{#if selectedImageIdx !== 0}
|
|
||||||
<div class="nav left" on:click={navigateLeft}>
|
|
||||||
<i class="ri-arrow-left-circle-fill" />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<img alt="preview" src={selectedImage.url} />
|
|
||||||
{#if selectedImageIdx !== files.length - 1}
|
|
||||||
<div class="nav right" on:click={navigateRight}>
|
|
||||||
<i class="ri-arrow-right-circle-fill" />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
{/if}
|
|
||||||
<i class={icons.fileUpload} />
|
|
||||||
<input {id} type="file" multiple on:change={handleFile} {...$$restProps} />
|
|
||||||
<i class="ri-upload-cloud-line" />
|
|
||||||
<p class="drop">Drop your files here</p>
|
|
||||||
<label for={id}>Select a file from your computer</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.dropzone {
|
|
||||||
padding: var(--spacing-l);
|
|
||||||
border: 2px dashed var(--grey-4);
|
|
||||||
text-align: center;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
border-radius: 10px;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fileDragged {
|
|
||||||
border: 2px dashed var(--grey-7);
|
|
||||||
background: var(--blue-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="file"] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
font-size: var(--font-size-s);
|
|
||||||
cursor: pointer;
|
|
||||||
overflow: hidden;
|
|
||||||
color: var(--grey-7);
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
min-width: auto;
|
|
||||||
outline: none;
|
|
||||||
font-feature-settings: "case" 1, "rlig" 1, "calt" 0;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
flex-shrink: 0;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drop {
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
font-size: var(--font-size-s);
|
|
||||||
margin: 12px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.nav {
|
|
||||||
padding: var(--spacing-xs);
|
|
||||||
position: absolute;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
bottom: var(--spacing-s);
|
|
||||||
border-radius: 5px;
|
|
||||||
transition: 0.2s transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
.left {
|
|
||||||
left: var(--spacing-s);
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
right: var(--spacing-s);
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
position: relative;
|
|
||||||
height: 300px;
|
|
||||||
background: var(--grey-7);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border-radius: 10px;
|
|
||||||
width: 100%;
|
|
||||||
box-shadow: 0 var(--spacing-s) 12px rgba(0, 0, 0, 0.15);
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
i {
|
|
||||||
font-size: 2rem;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
i:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--background);
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-icon {
|
|
||||||
color: var(--background);
|
|
||||||
font-size: 2em;
|
|
||||||
margin-right: var(--spacing-s);
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding: 0;
|
|
||||||
display: grid;
|
|
||||||
grid-gap: var(--spacing-s);
|
|
||||||
list-style-type: none;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
position: absolute;
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
rgb(255, 255, 255),
|
|
||||||
rgba(255, 255, 255, 0)
|
|
||||||
);
|
|
||||||
width: 100%;
|
|
||||||
border-top-left-radius: 10px;
|
|
||||||
border-top-right-radius: 10px;
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
header > div {
|
|
||||||
color: var(--ink);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 12px;
|
|
||||||
margin-left: var(--spacing-m);
|
|
||||||
width: 60%;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filename {
|
|
||||||
overflow: hidden;
|
|
||||||
margin-left: 5px;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
header > p {
|
|
||||||
color: var(--grey-5);
|
|
||||||
margin-right: var(--spacing-m);
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button {
|
|
||||||
position: absolute;
|
|
||||||
top: var(--spacing-s);
|
|
||||||
right: var(--spacing-s);
|
|
||||||
padding: var(--spacing-s);
|
|
||||||
border-radius: 10px;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button i {
|
|
||||||
font-size: 2em;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--red);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,17 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Dropzone from "./Dropzone.svelte";
|
|
||||||
|
|
||||||
async function processFiles(files) {
|
|
||||||
console.log("Processing", files);
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFileTooLarge() {
|
|
||||||
alert("File too large.");
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="dropzone">
|
|
||||||
<Dropzone {processFiles} {handleFileTooLarge} />
|
|
||||||
</View>
|
|
|
@ -1,5 +0,0 @@
|
||||||
export const FILE_TYPES = {
|
|
||||||
IMAGE: ["png", "tiff", "gif", "raw", "jpg", "jpeg", "svg"],
|
|
||||||
CODE: ["js", "rs", "py", "java", "rb", "hs", "yml"],
|
|
||||||
DOCUMENT: ["odf", "docx", "doc", "pdf", "csv"],
|
|
||||||
}
|
|
|
@ -1,140 +1,22 @@
|
||||||
<script>
|
<script>
|
||||||
|
import Field from "./Field.svelte"
|
||||||
|
import Checkbox from "./Core/Checkbox.svelte"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = null
|
||||||
|
export let label = null
|
||||||
|
export let labelPosition = "above"
|
||||||
|
export let text = null
|
||||||
|
export let disabled = false
|
||||||
|
export let error = null
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = e => {
|
||||||
export let checked = false
|
value = e.detail
|
||||||
export let value
|
dispatch("change", e.detail)
|
||||||
export let name
|
|
||||||
export let disabled
|
|
||||||
|
|
||||||
function handleChange() {
|
|
||||||
if (disabled) return
|
|
||||||
checked = !checked
|
|
||||||
dispatch("change", checked)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container">
|
<Field {label} {labelPosition} {disabled} {error}>
|
||||||
<input
|
<Checkbox {error} {disabled} {text} {value} on:change={onChange} />
|
||||||
{disabled}
|
</Field>
|
||||||
on:change={handleChange}
|
|
||||||
{value}
|
|
||||||
bind:checked
|
|
||||||
type="checkbox"
|
|
||||||
{name}
|
|
||||||
class="checkbox"
|
|
||||||
id={value} />
|
|
||||||
<div class="checkbox-container" on:click={handleChange}>
|
|
||||||
<div class:disabled class="check-div" class:checked>
|
|
||||||
<div class="tick_mark" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
gap: var(--spacing-s);
|
|
||||||
}
|
|
||||||
.checkbox-container {
|
|
||||||
position: relative;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-div {
|
|
||||||
position: relative;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 0.2s ease transform, 0.2s ease background-color,
|
|
||||||
0.2s ease box-shadow;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-div:before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background-color: var(--background);
|
|
||||||
transform: translateY(-50%);
|
|
||||||
transition: 0.2s ease width, 0.2s ease height;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-div:active {
|
|
||||||
transform: translateY(-50%) scale(0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tick_mark {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 6px;
|
|
||||||
width: 5px;
|
|
||||||
height: 4px;
|
|
||||||
margin: 0 auto;
|
|
||||||
transform: rotateZ(-40deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tick_mark:before,
|
|
||||||
.tick_mark:after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
background-color: var(--ink);
|
|
||||||
border-radius: 2px;
|
|
||||||
opacity: 0;
|
|
||||||
transition: 0.2s ease transform, 0.2s ease opacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tick_mark:before {
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 2px;
|
|
||||||
height: 6px;
|
|
||||||
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.23);
|
|
||||||
transform: translateY(-68px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tick_mark:after {
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 12px;
|
|
||||||
height: 2px;
|
|
||||||
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.23);
|
|
||||||
transform: translateX(78px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-div.disabled:active {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checked {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
}
|
|
||||||
.checked.disabled {
|
|
||||||
background-color: var(--grey-5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.checked:before {
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checked .tick_mark:before,
|
|
||||||
.checked .tick_mark:after {
|
|
||||||
transform: translate(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Checkbox from "./Checkbox.svelte";
|
|
||||||
|
|
||||||
let checked = false
|
|
||||||
|
|
||||||
let menu = [
|
|
||||||
{text: 'Cookies and cream', checked: false},
|
|
||||||
{text: 'Mint choc chip', checked: false},
|
|
||||||
{text: 'Raspberry ripple', checked: true}
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="Single checkbox">
|
|
||||||
<Checkbox bind:checked value="value">
|
|
||||||
<label for="value">One single checkbox with text</label>
|
|
||||||
</Checkbox>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Single disabled checkbox">
|
|
||||||
<Checkbox disabled checked value="value">
|
|
||||||
<label for="someOtherValue">A disabled checkbox</label>
|
|
||||||
</Checkbox>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="No text">
|
|
||||||
<Checkbox bind:checked value="somevalue" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
## Multiple checkboxes
|
|
||||||
Use an array and an each block to use multiple checkboxes
|
|
||||||
```svelte
|
|
||||||
<script>
|
|
||||||
let menu = [
|
|
||||||
{text: 'Cookies and cream', checked: false},
|
|
||||||
{text: 'Mint choc chip', checked: false},
|
|
||||||
{text: 'Raspberry ripple', checked: true}
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#each menu as {text, checked}}
|
|
||||||
<Checkbox value={text} bind:checked>
|
|
||||||
<label for={text}>{text}</label>
|
|
||||||
</Checkbox>
|
|
||||||
{/each}
|
|
||||||
```
|
|
||||||
|
|
||||||
<View name="Multiple checkboxes">
|
|
||||||
<div class="container">
|
|
||||||
{#each menu as {text, checked}}
|
|
||||||
<Checkbox value={text} bind:checked>
|
|
||||||
<label for={text}>{text}</label>
|
|
||||||
</Checkbox>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
label {
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<script>
|
||||||
|
import Field from "./Field.svelte"
|
||||||
|
import Combobox from "./Core/Combobox.svelte"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = null
|
||||||
|
export let label = undefined
|
||||||
|
export let disabled = false
|
||||||
|
export let labelPosition = "above"
|
||||||
|
export let error = null
|
||||||
|
export let placeholder = "Choose an option"
|
||||||
|
export let options = []
|
||||||
|
export let getOptionLabel = option => extractProperty(option, "label")
|
||||||
|
export let getOptionValue = option => extractProperty(option, "value")
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = e => {
|
||||||
|
value = e.detail
|
||||||
|
dispatch("change", e.detail)
|
||||||
|
}
|
||||||
|
const extractProperty = (value, property) => {
|
||||||
|
if (value && typeof value === "object") {
|
||||||
|
return value[property]
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Field {label} {labelPosition} {disabled} {error}>
|
||||||
|
<Combobox
|
||||||
|
{error}
|
||||||
|
{disabled}
|
||||||
|
{value}
|
||||||
|
{options}
|
||||||
|
{placeholder}
|
||||||
|
{getOptionLabel}
|
||||||
|
{getOptionValue}
|
||||||
|
on:change={onChange}
|
||||||
|
/>
|
||||||
|
</Field>
|
|
@ -0,0 +1,47 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/checkbox/dist/index-vars.css"
|
||||||
|
import "@spectrum-css/fieldgroup/dist/index-vars.css"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = false
|
||||||
|
export let error = null
|
||||||
|
export let id = null
|
||||||
|
export let text = null
|
||||||
|
export let disabled = false
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = event => {
|
||||||
|
dispatch("change", event.target.checked)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label
|
||||||
|
class="spectrum-Checkbox spectrum-Checkbox--sizeM spectrum-Checkbox--emphasized"
|
||||||
|
class:is-invalid={!!error}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
checked={value}
|
||||||
|
{disabled}
|
||||||
|
on:change={onChange}
|
||||||
|
type="checkbox"
|
||||||
|
class="spectrum-Checkbox-input"
|
||||||
|
{id}
|
||||||
|
/>
|
||||||
|
<span class="spectrum-Checkbox-box">
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Checkbox-checkmark"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||||
|
</svg>
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-UIIcon-Dash100 spectrum-Checkbox-partialCheckmark"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-css-icon-Dash100" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span class="spectrum-Checkbox-label">{text || ""}</span>
|
||||||
|
</label>
|
|
@ -0,0 +1,136 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/inputgroup/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"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = null
|
||||||
|
export let id = null
|
||||||
|
export let placeholder = "Choose an option"
|
||||||
|
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
|
||||||
|
let focus = false
|
||||||
|
$: fieldText = getFieldText(value, options, placeholder)
|
||||||
|
|
||||||
|
const getFieldText = (value, options, placeholder) => {
|
||||||
|
// Always use placeholder if no value
|
||||||
|
if (value == null || value === "") {
|
||||||
|
return placeholder || "Choose an option"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for options to load if there is a value but no options
|
||||||
|
if (!options?.length) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the label if the selected option is found, otherwise raw value
|
||||||
|
const selected = options.find(option => getOptionValue(option) === value)
|
||||||
|
return selected ? getOptionLabel(selected) : value
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectOption = value => {
|
||||||
|
dispatch("change", value)
|
||||||
|
open = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChange = e => {
|
||||||
|
selectOption(e.target.value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="spectrum-InputGroup" class:is-focused={open || focus}>
|
||||||
|
<div
|
||||||
|
class="spectrum-Textfield spectrum-InputGroup-textfield"
|
||||||
|
class:is-disabled={!!error}
|
||||||
|
class:is-focused={open || focus}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
on:focus={() => (focus = true)}
|
||||||
|
on:blur={() => (focus = false)}
|
||||||
|
on:change={onChange}
|
||||||
|
{value}
|
||||||
|
{placeholder}
|
||||||
|
class="spectrum-Textfield-input spectrum-InputGroup-input"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="spectrum-Picker spectrum-Picker--sizeM spectrum-InputGroup-button"
|
||||||
|
tabindex="-1"
|
||||||
|
aria-haspopup="true"
|
||||||
|
disabled={!!error}
|
||||||
|
on:click={() => (open = true)}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon spectrum-InputGroup-icon"
|
||||||
|
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 is-open"
|
||||||
|
>
|
||||||
|
<ul class="spectrum-Menu" role="listbox">
|
||||||
|
{#if options && Array.isArray(options)}
|
||||||
|
{#each options as option}
|
||||||
|
<li
|
||||||
|
class="spectrum-Menu-item"
|
||||||
|
class:is-selected={getOptionValue(option) === value}
|
||||||
|
role="option"
|
||||||
|
aria-selected="true"
|
||||||
|
tabindex="0"
|
||||||
|
on:click={() => selectOption(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}
|
||||||
|
{/if}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.spectrum-InputGroup {
|
||||||
|
min-width: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.spectrum-Textfield-input {
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
.overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
.spectrum-Popover {
|
||||||
|
max-height: 240px;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 999;
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,149 @@
|
||||||
|
<script>
|
||||||
|
import Flatpickr from "svelte-flatpickr"
|
||||||
|
import "flatpickr/dist/flatpickr.css"
|
||||||
|
import "@spectrum-css/inputgroup/dist/index-vars.css"
|
||||||
|
import "@spectrum-css/textfield/dist/index-vars.css"
|
||||||
|
import "@spectrum-css/picker/dist/index-vars.css"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
import { generateID } from "../../utils/helpers"
|
||||||
|
|
||||||
|
export let id = null
|
||||||
|
export let disabled = false
|
||||||
|
export let error = null
|
||||||
|
export let isPlaceholder = false
|
||||||
|
export let enableTime = true
|
||||||
|
export let value = null
|
||||||
|
export let placeholder = null
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const flatpickrId = `${generateID()}-wrapper`
|
||||||
|
let open = false
|
||||||
|
let flatpickr
|
||||||
|
$: flatpickrOptions = {
|
||||||
|
element: `#${flatpickrId}`,
|
||||||
|
enableTime: enableTime || false,
|
||||||
|
altInput: true,
|
||||||
|
altFormat: enableTime ? "F j Y, H:i" : "F j, Y",
|
||||||
|
wrap: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChange = event => {
|
||||||
|
const [dates] = event.detail
|
||||||
|
dispatch("change", dates[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearDateOnBackspace = event => {
|
||||||
|
if (["Backspace", "Clear", "Delete"].includes(event.key)) {
|
||||||
|
dispatch("change", null)
|
||||||
|
flatpickr.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onOpen = () => {
|
||||||
|
open = true
|
||||||
|
document.addEventListener("keyup", clearDateOnBackspace)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
open = false
|
||||||
|
document.removeEventListener("keyup", clearDateOnBackspace)
|
||||||
|
|
||||||
|
// Manually blur all input fields since flatpickr creates a second
|
||||||
|
// duplicate input field.
|
||||||
|
// We need to blur both because the focus styling does not get properly
|
||||||
|
// applied.
|
||||||
|
const els = document.querySelectorAll(`#${flatpickrId} input`)
|
||||||
|
els.forEach(el => el.blur())
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Flatpickr
|
||||||
|
bind:flatpickr
|
||||||
|
{value}
|
||||||
|
on:open={onOpen}
|
||||||
|
on:close={onClose}
|
||||||
|
options={flatpickrOptions}
|
||||||
|
on:change={handleChange}
|
||||||
|
element={`#${flatpickrId}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
id={flatpickrId}
|
||||||
|
class:is-disabled={disabled}
|
||||||
|
class:is-invalid={!!error}
|
||||||
|
class="flatpickr spectrum-InputGroup spectrum-Datepicker"
|
||||||
|
class:is-focused={open}
|
||||||
|
aria-readonly="false"
|
||||||
|
aria-required="false"
|
||||||
|
aria-haspopup="true"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
on:click={flatpickr?.open}
|
||||||
|
class="spectrum-Textfield spectrum-InputGroup-textfield"
|
||||||
|
class:is-disabled={disabled}
|
||||||
|
class:is-invalid={!!error}
|
||||||
|
>
|
||||||
|
{#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
|
||||||
|
data-input
|
||||||
|
type="text"
|
||||||
|
{disabled}
|
||||||
|
class="spectrum-Textfield-input spectrum-InputGroup-input"
|
||||||
|
{placeholder}
|
||||||
|
{id}
|
||||||
|
{value}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="spectrum-Picker spectrum-Picker--sizeM spectrum-InputGroup-button"
|
||||||
|
tabindex="-1"
|
||||||
|
{disabled}
|
||||||
|
class:is-invalid={!!error}
|
||||||
|
on:click={flatpickr?.open}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-Icon--sizeM"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
aria-label="Calendar"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-icon-18-Calendar" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Flatpickr>
|
||||||
|
{#if open}
|
||||||
|
<div class="overlay" on:mousedown|self={flatpickr?.close} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.spectrum-Textfield-input {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.spectrum-Textfield:not(.is-disabled):hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.flatpickr {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.flatpickr .spectrum-Textfield {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,350 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/dropzone/dist/index-vars.css"
|
||||||
|
import "@spectrum-css/typography/dist/index-vars.css"
|
||||||
|
import "@spectrum-css/illustratedmessage/dist/index-vars.css"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
import { generateID } from "../../utils/helpers"
|
||||||
|
import Icon from "../../Icon/Icon.svelte"
|
||||||
|
|
||||||
|
const BYTES_IN_KB = 1000
|
||||||
|
const BYTES_IN_MB = 1000000
|
||||||
|
|
||||||
|
export let value = []
|
||||||
|
export let id = null
|
||||||
|
export let disabled = false
|
||||||
|
export let fileSizeLimit = BYTES_IN_MB * 20
|
||||||
|
export let processFiles = null
|
||||||
|
export let handleFileTooLarge = null
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const imageExtensions = [
|
||||||
|
"png",
|
||||||
|
"tiff",
|
||||||
|
"gif",
|
||||||
|
"raw",
|
||||||
|
"jpg",
|
||||||
|
"jpeg",
|
||||||
|
"svg",
|
||||||
|
"bmp",
|
||||||
|
"jfif",
|
||||||
|
]
|
||||||
|
const onChange = event => {
|
||||||
|
dispatch("change", event.target.checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fieldId = id || generateID()
|
||||||
|
let selectedImageIdx = 0
|
||||||
|
let fileDragged = false
|
||||||
|
$: selectedImage = value?.[selectedImageIdx] ?? null
|
||||||
|
$: fileCount = value?.length ?? 0
|
||||||
|
$: isImage = imageExtensions.includes(selectedImage?.extension?.toLowerCase())
|
||||||
|
|
||||||
|
async function processFileList(fileList) {
|
||||||
|
if (
|
||||||
|
handleFileTooLarge &&
|
||||||
|
Array.from(fileList).some(file => file.size >= fileSizeLimit)
|
||||||
|
) {
|
||||||
|
handleFileTooLarge(fileSizeLimit, value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (processFiles) {
|
||||||
|
const processedFiles = await processFiles(fileList)
|
||||||
|
const newValue = [...value, ...processedFiles]
|
||||||
|
dispatch("change", newValue)
|
||||||
|
selectedImageIdx = newValue.length - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeFile() {
|
||||||
|
dispatch(
|
||||||
|
"change",
|
||||||
|
value.filter((x, idx) => idx !== selectedImageIdx)
|
||||||
|
)
|
||||||
|
selectedImageIdx = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateLeft() {
|
||||||
|
selectedImageIdx -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateRight() {
|
||||||
|
selectedImageIdx += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFile(evt) {
|
||||||
|
processFileList(evt.target.files)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragOver(evt) {
|
||||||
|
evt.preventDefault()
|
||||||
|
fileDragged = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragLeave(evt) {
|
||||||
|
evt.preventDefault()
|
||||||
|
fileDragged = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrop(evt) {
|
||||||
|
evt.preventDefault()
|
||||||
|
processFileList(evt.dataTransfer.files)
|
||||||
|
fileDragged = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
{#if selectedImage}
|
||||||
|
<div class="gallery">
|
||||||
|
<div class="title">
|
||||||
|
<div class="filename">{selectedImage.name}</div>
|
||||||
|
<div class="filesize">
|
||||||
|
{#if selectedImage.size <= BYTES_IN_MB}
|
||||||
|
{`${selectedImage.size / BYTES_IN_KB} KB`}
|
||||||
|
{:else}{`${selectedImage.size / BYTES_IN_MB} MB`}{/if}
|
||||||
|
</div>
|
||||||
|
{#if !disabled}
|
||||||
|
<div class="delete-button" on:click={removeFile}>
|
||||||
|
<Icon name="Close" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#if isImage}
|
||||||
|
<img alt="preview" src={selectedImage.url} />
|
||||||
|
{:else}
|
||||||
|
<div class="placeholder">
|
||||||
|
<div class="extension">{selectedImage.extension}</div>
|
||||||
|
<div>Preview not supported</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div
|
||||||
|
class="nav left"
|
||||||
|
class:visible={selectedImageIdx > 0}
|
||||||
|
on:click={navigateLeft}
|
||||||
|
>
|
||||||
|
<Icon name="ChevronLeft" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="nav right"
|
||||||
|
class:visible={selectedImageIdx < fileCount - 1}
|
||||||
|
on:click={navigateRight}
|
||||||
|
>
|
||||||
|
<Icon name="ChevronRight" />
|
||||||
|
</div>
|
||||||
|
<div class="footer">File {selectedImageIdx + 1} of {fileCount}</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div
|
||||||
|
class="spectrum-Dropzone"
|
||||||
|
class:disabled
|
||||||
|
role="region"
|
||||||
|
tabindex="0"
|
||||||
|
on:dragover={handleDragOver}
|
||||||
|
on:dragleave={handleDragLeave}
|
||||||
|
on:dragenter={handleDragOver}
|
||||||
|
on:drop={handleDrop}
|
||||||
|
class:is-dragged={fileDragged}
|
||||||
|
>
|
||||||
|
<div class="spectrum-IllustratedMessage spectrum-IllustratedMessage--cta">
|
||||||
|
<input
|
||||||
|
id={fieldId}
|
||||||
|
{disabled}
|
||||||
|
type="file"
|
||||||
|
multiple
|
||||||
|
on:change={handleFile}
|
||||||
|
/>
|
||||||
|
<svg
|
||||||
|
class="spectrum-IllustratedMessage-illustration"
|
||||||
|
width="125"
|
||||||
|
height="60"
|
||||||
|
viewBox="0 0 199 97.7"
|
||||||
|
><defs>
|
||||||
|
<style>
|
||||||
|
.cls-1,
|
||||||
|
.cls-2 {
|
||||||
|
fill: none;
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-linejoin: round;
|
||||||
|
}
|
||||||
|
.cls-1 {
|
||||||
|
stroke-width: 3px;
|
||||||
|
}
|
||||||
|
.cls-2 {
|
||||||
|
stroke-width: 2px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
class="cls-1"
|
||||||
|
d="M110.53,85.66,100.26,95.89a1.09,1.09,0,0,1-1.52,0L88.47,85.66"
|
||||||
|
/>
|
||||||
|
<line class="cls-1" x1="99.5" y1="95.5" x2="99.5" y2="58.5" />
|
||||||
|
<path class="cls-1" d="M105.5,73.5h19a2,2,0,0,0,2-2v-43" />
|
||||||
|
<path
|
||||||
|
class="cls-1"
|
||||||
|
d="M126.5,22.5h-19a2,2,0,0,1-2-2V1.5h-31a2,2,0,0,0-2,2v68a2,2,0,0,0,2,2h19"
|
||||||
|
/>
|
||||||
|
<line class="cls-1" x1="105.5" y1="1.5" x2="126.5" y2="22.5" />
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M47.93,50.49a5,5,0,1,0-4.83-5A4.93,4.93,0,0,0,47.93,50.49Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M36.6,65.93,42.05,60A2.06,2.06,0,0,1,45,60l12.68,13.2"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M3.14,73.23,22.42,53.76a1.65,1.65,0,0,1,2.38,0l19.05,19.7"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-1"
|
||||||
|
d="M139.5,36.5H196A1.49,1.49,0,0,1,197.5,38V72A1.49,1.49,0,0,1,196,73.5H141A1.49,1.49,0,0,1,139.5,72V32A1.49,1.49,0,0,1,141,30.5H154a2.43,2.43,0,0,1,1.67.66l6,5.66"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
class="cls-1"
|
||||||
|
x="1.5"
|
||||||
|
y="34.5"
|
||||||
|
width="58"
|
||||||
|
height="39"
|
||||||
|
rx="2"
|
||||||
|
ry="2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<h2
|
||||||
|
class="spectrum-Heading spectrum-Heading--sizeL spectrum-Heading--light spectrum-IllustratedMessage-heading"
|
||||||
|
>
|
||||||
|
Drag and drop your file
|
||||||
|
</h2>
|
||||||
|
{#if !disabled}
|
||||||
|
<p
|
||||||
|
class="spectrum-Body spectrum-Body--sizeS spectrum-IllustratedMessage-description"
|
||||||
|
>
|
||||||
|
<label for={fieldId} class="spectrum-Link"
|
||||||
|
>Select a file to upload</label
|
||||||
|
>
|
||||||
|
<br />
|
||||||
|
from your computer
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
--spectrum-dropzone-padding: var(--spectrum-global-dimension-size-400);
|
||||||
|
--spectrum-heading-l-text-size: var(
|
||||||
|
--spectrum-global-dimension-font-size-400
|
||||||
|
);
|
||||||
|
}
|
||||||
|
.container * {
|
||||||
|
font-family: "Inter", sans-serif !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery,
|
||||||
|
.spectrum-Dropzone {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
input[type="file"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
|
background-color: var(--spectrum-global-color-gray-50);
|
||||||
|
color: var(--spectrum-alias-text-color);
|
||||||
|
font-size: var(--spectrum-alias-item-text-size-m);
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: var(--spectrum-alias-border-size-thin)
|
||||||
|
var(--spectrum-alias-border-color) solid;
|
||||||
|
border-radius: var(--spectrum-alias-border-radius-regular);
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.placeholder,
|
||||||
|
img {
|
||||||
|
height: 120px;
|
||||||
|
max-width: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
margin: 20px 30px;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
.filename {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 0;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.placeholder {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.extension {
|
||||||
|
color: var(--spectrum-global-color-gray-600);
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
padding: var(--spacing-xs);
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: none;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
.nav.visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.nav:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
.left {
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
.right {
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
font-size: 2rem;
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
i:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--background);
|
||||||
|
}
|
||||||
|
.delete-button {
|
||||||
|
transition: all 0.3s;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.delete-button i {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
.delete-button:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spectrum-Dropzone.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
background-color: var(--spectrum-global-color-gray-200);
|
||||||
|
}
|
||||||
|
.disabled .spectrum-Heading--sizeL {
|
||||||
|
color: var(--spectrum-alias-text-color-disabled);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,82 @@
|
||||||
|
<script>
|
||||||
|
import Picker from "./Picker.svelte"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = []
|
||||||
|
export let id = 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()
|
||||||
|
$: selectedLookupMap = getSelectedLookupMap(value)
|
||||||
|
$: optionLookupMap = getOptionLookupMap(options)
|
||||||
|
$: fieldText = getFieldText(value, optionLookupMap, placeholder)
|
||||||
|
$: isOptionSelected = optionValue => selectedLookupMap[optionValue] === true
|
||||||
|
$: toggleOption = makeToggleOption(selectedLookupMap, value)
|
||||||
|
|
||||||
|
const getFieldText = (value, map, placeholder) => {
|
||||||
|
if (value?.length) {
|
||||||
|
if (!map) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
const vals = value.map(option => map[option] || option).join(", ")
|
||||||
|
return `(${value.length}) ${vals}`
|
||||||
|
} else {
|
||||||
|
return placeholder || "Choose some options"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSelectedLookupMap = value => {
|
||||||
|
let map = {}
|
||||||
|
if (value?.length) {
|
||||||
|
value.forEach(option => {
|
||||||
|
if (option) {
|
||||||
|
map[option] = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOptionLookupMap = options => {
|
||||||
|
let map = null
|
||||||
|
if (options?.length) {
|
||||||
|
map = {}
|
||||||
|
options.forEach((option, idx) => {
|
||||||
|
const optionValue = getOptionValue(option, idx)
|
||||||
|
if (optionValue != null) {
|
||||||
|
map[optionValue] = getOptionLabel(option, idx) || ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeToggleOption = (map, value) => {
|
||||||
|
return optionValue => {
|
||||||
|
if (map[optionValue]) {
|
||||||
|
const filtered = value.filter(option => option !== optionValue)
|
||||||
|
dispatch("change", filtered)
|
||||||
|
} else {
|
||||||
|
dispatch("change", [...value, optionValue])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Picker
|
||||||
|
{id}
|
||||||
|
{error}
|
||||||
|
{disabled}
|
||||||
|
{fieldText}
|
||||||
|
{options}
|
||||||
|
isPlaceholder={!value?.length}
|
||||||
|
{isOptionSelected}
|
||||||
|
{getOptionLabel}
|
||||||
|
{getOptionValue}
|
||||||
|
onSelectOption={toggleOption}
|
||||||
|
/>
|
|
@ -0,0 +1,132 @@
|
||||||
|
<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"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
import clickOutside from "../../Actions/click_outside"
|
||||||
|
|
||||||
|
export let id = 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
|
||||||
|
export let readonly = false
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onClick = e => {
|
||||||
|
dispatch("click")
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
open = true
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button
|
||||||
|
{id}
|
||||||
|
class="spectrum-Picker spectrum-Picker--sizeM"
|
||||||
|
{disabled}
|
||||||
|
class:is-invalid={!!error}
|
||||||
|
class:is-open={open}
|
||||||
|
aria-haspopup="listbox"
|
||||||
|
on:mousedown={onClick}
|
||||||
|
>
|
||||||
|
<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
|
||||||
|
use:clickOutside={() => (open = false)}
|
||||||
|
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}
|
||||||
|
{#if options && Array.isArray(options)}
|
||||||
|
{#each options as option, idx}
|
||||||
|
<li
|
||||||
|
class="spectrum-Menu-item"
|
||||||
|
class:is-selected={isOptionSelected(getOptionValue(option, idx))}
|
||||||
|
role="option"
|
||||||
|
aria-selected="true"
|
||||||
|
tabindex="0"
|
||||||
|
on:click={() => onSelectOption(getOptionValue(option, idx))}
|
||||||
|
>
|
||||||
|
<span class="spectrum-Menu-itemLabel"
|
||||||
|
>{getOptionLabel(option, idx)}</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}
|
||||||
|
{/if}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.spectrum-Popover {
|
||||||
|
max-height: 240px;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 999;
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
.spectrum-Picker {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.spectrum-Picker-label {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/fieldgroup/dist/index-vars.css"
|
||||||
|
import "@spectrum-css/radio/dist/index-vars.css"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let direction = "vertical"
|
||||||
|
export let value = null
|
||||||
|
export let options = []
|
||||||
|
export let error = null
|
||||||
|
export let disabled = false
|
||||||
|
export let getOptionLabel = option => option
|
||||||
|
export let getOptionValue = option => option
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = e => dispatch("change", e.target.value)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class={`spectrum-FieldGroup spectrum-FieldGroup--${direction}`}>
|
||||||
|
{#if options && Array.isArray(options)}
|
||||||
|
{#each options as option}
|
||||||
|
<div
|
||||||
|
title={getOptionLabel(option)}
|
||||||
|
class="spectrum-Radio spectrum-FieldGroup-item spectrum-Radio--emphasized"
|
||||||
|
class:is-invalid={!!error}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
on:change={onChange}
|
||||||
|
bind:group={value}
|
||||||
|
value={getOptionValue(option)}
|
||||||
|
type="radio"
|
||||||
|
class="spectrum-Radio-input"
|
||||||
|
{disabled}
|
||||||
|
/>
|
||||||
|
<span class="spectrum-Radio-button" />
|
||||||
|
<label class="spectrum-Radio-label">{getOptionLabel(option)}</label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</div>
|
|
@ -0,0 +1,87 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/search/dist/index-vars.css"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = ""
|
||||||
|
export let placeholder = null
|
||||||
|
export let disabled = false
|
||||||
|
export let id = null
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
let focus = false
|
||||||
|
|
||||||
|
const updateValue = value => {
|
||||||
|
dispatch("change", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFocus = () => {
|
||||||
|
focus = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur = event => {
|
||||||
|
focus = false
|
||||||
|
updateValue(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateValueOnEnter = event => {
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
updateValue(event.target.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="spectrum-Search" class:is-disabled={disabled}>
|
||||||
|
<div
|
||||||
|
class="spectrum-Textfield"
|
||||||
|
class:is-focused={focus}
|
||||||
|
class:is-disabled={disabled}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-icon"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-icon-18-Magnify" />
|
||||||
|
</svg>
|
||||||
|
<input
|
||||||
|
on:click
|
||||||
|
on:keyup={updateValueOnEnter}
|
||||||
|
{disabled}
|
||||||
|
{id}
|
||||||
|
value={value || ""}
|
||||||
|
placeholder={placeholder || ""}
|
||||||
|
on:blur={onBlur}
|
||||||
|
on:focus={onFocus}
|
||||||
|
on:input
|
||||||
|
type="search"
|
||||||
|
class="spectrum-Textfield-input spectrum-Search-input"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
on:click={() => updateValue("")}
|
||||||
|
type="reset"
|
||||||
|
class="spectrum-ClearButton spectrum-Search-clearButton"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-UIIcon-Cross75"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-css-icon-Cross75" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.spectrum-Search,
|
||||||
|
.spectrum-Textfield {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.spectrum-Search-input {
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
.is-disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,58 @@
|
||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
import Picker from "./Picker.svelte"
|
||||||
|
|
||||||
|
export let value = null
|
||||||
|
export let id = null
|
||||||
|
export let placeholder = "Choose an option"
|
||||||
|
export let disabled = false
|
||||||
|
export let error = null
|
||||||
|
export let options = []
|
||||||
|
export let getOptionLabel = option => option
|
||||||
|
export let getOptionValue = option => option
|
||||||
|
export let readonly = false
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
let open = false
|
||||||
|
$: fieldText = getFieldText(value, options, placeholder)
|
||||||
|
|
||||||
|
const getFieldText = (value, options, placeholder) => {
|
||||||
|
// Always use placeholder if no value
|
||||||
|
if (value == null || value === "") {
|
||||||
|
return placeholder || "Choose an option"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for options to load if there is a value but no options
|
||||||
|
if (!options?.length) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the label if the selected option is found, otherwide raw value
|
||||||
|
const index = options.findIndex(
|
||||||
|
(option, idx) => getOptionValue(option, idx) === value
|
||||||
|
)
|
||||||
|
return index !== -1 ? getOptionLabel(options[index], index) : value
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectOption = value => {
|
||||||
|
dispatch("change", value)
|
||||||
|
open = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Picker
|
||||||
|
on:click
|
||||||
|
bind:open
|
||||||
|
{id}
|
||||||
|
{error}
|
||||||
|
{disabled}
|
||||||
|
{readonly}
|
||||||
|
{fieldText}
|
||||||
|
{options}
|
||||||
|
{getOptionLabel}
|
||||||
|
{getOptionValue}
|
||||||
|
isPlaceholder={value == null || value === ""}
|
||||||
|
placeholderOption={placeholder}
|
||||||
|
isOptionSelected={option => option === value}
|
||||||
|
onSelectOption={selectOption}
|
||||||
|
/>
|
|
@ -0,0 +1,28 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/switch/dist/index-vars.css"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = false
|
||||||
|
export let error = null
|
||||||
|
export let id = null
|
||||||
|
export let text = null
|
||||||
|
export let disabled = false
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = event => {
|
||||||
|
dispatch("change", event.target.checked)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="spectrum-Switch spectrum-Switch--emphasized">
|
||||||
|
<input
|
||||||
|
checked={value}
|
||||||
|
{disabled}
|
||||||
|
on:change={onChange}
|
||||||
|
{id}
|
||||||
|
type="checkbox"
|
||||||
|
class="spectrum-Switch-input"
|
||||||
|
/>
|
||||||
|
<span class="spectrum-Switch-switch" />
|
||||||
|
<label class="spectrum-Switch-label" for={id}>{text}</label>
|
||||||
|
</div>
|
|
@ -0,0 +1,60 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/textfield/dist/index-vars.css"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = ""
|
||||||
|
export let placeholder = null
|
||||||
|
export let disabled = false
|
||||||
|
export let error = null
|
||||||
|
export let id = null
|
||||||
|
export const getCaretPosition = () => ({
|
||||||
|
start: textarea.selectionStart,
|
||||||
|
end: textarea.selectionEnd,
|
||||||
|
})
|
||||||
|
|
||||||
|
let focus = false
|
||||||
|
let textarea
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = event => {
|
||||||
|
dispatch("change", event.target.value)
|
||||||
|
focus = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="spectrum-Textfield spectrum-Textfield--multiline"
|
||||||
|
class:is-invalid={!!error}
|
||||||
|
class:is-disabled={disabled}
|
||||||
|
class:is-focused={focus}
|
||||||
|
>
|
||||||
|
{#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}
|
||||||
|
<!-- prettier-ignore -->
|
||||||
|
<textarea
|
||||||
|
bind:this={textarea}
|
||||||
|
placeholder={placeholder || ""}
|
||||||
|
class="spectrum-Textfield-input"
|
||||||
|
{disabled}
|
||||||
|
{id}
|
||||||
|
on:focus={() => (focus = true)}
|
||||||
|
on:blur={onChange}
|
||||||
|
>{value || ""}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.spectrum-Textfield {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 80px !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,87 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/textfield/dist/index-vars.css"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = ""
|
||||||
|
export let placeholder = null
|
||||||
|
export let type = "text"
|
||||||
|
export let disabled = false
|
||||||
|
export let error = null
|
||||||
|
export let id = null
|
||||||
|
export let readonly = false
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
let focus = false
|
||||||
|
|
||||||
|
const updateValue = value => {
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (type === "number") {
|
||||||
|
const float = parseFloat(value)
|
||||||
|
value = isNaN(float) ? null : float
|
||||||
|
}
|
||||||
|
dispatch("change", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFocus = () => {
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
focus = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur = event => {
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
focus = false
|
||||||
|
updateValue(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateValueOnEnter = event => {
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
updateValue(event.target.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="spectrum-Textfield"
|
||||||
|
class:is-invalid={!!error}
|
||||||
|
class:is-disabled={disabled}
|
||||||
|
class:is-focused={focus}
|
||||||
|
>
|
||||||
|
{#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:click
|
||||||
|
on:keyup={updateValueOnEnter}
|
||||||
|
{disabled}
|
||||||
|
{readonly}
|
||||||
|
{id}
|
||||||
|
value={value || ""}
|
||||||
|
placeholder={placeholder || ""}
|
||||||
|
on:blur={onBlur}
|
||||||
|
on:focus={onFocus}
|
||||||
|
on:input
|
||||||
|
{type}
|
||||||
|
class="spectrum-Textfield-input"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.spectrum-Textfield {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,11 @@
|
||||||
|
export { default as CoreTextField } from "./TextField.svelte"
|
||||||
|
export { default as CoreSelect } from "./Select.svelte"
|
||||||
|
export { default as CoreMultiselect } from "./Multiselect.svelte"
|
||||||
|
export { default as CoreCheckbox } from "./Checkbox.svelte"
|
||||||
|
export { default as CoreRadioGroup } from "./RadioGroup.svelte"
|
||||||
|
export { default as CoreTextArea } from "./TextArea.svelte"
|
||||||
|
export { default as CoreCombobox } from "./Combobox.svelte"
|
||||||
|
export { default as CoreSwitch } from "./Switch.svelte"
|
||||||
|
export { default as CoreSearch } from "./Search.svelte"
|
||||||
|
export { default as CoreDatePicker } from "./DatePicker.svelte"
|
||||||
|
export { default as CoreDropzone } from "./Dropzone.svelte"
|
|
@ -1,158 +0,0 @@
|
||||||
<script>
|
|
||||||
import Icon from "../Icons/Icon.svelte"
|
|
||||||
import Label from "../Styleguide/Label.svelte"
|
|
||||||
import { createEventDispatcher } from "svelte"
|
|
||||||
|
|
||||||
export let label = undefined
|
|
||||||
export let value = ""
|
|
||||||
export let name = undefined
|
|
||||||
export let thin = false
|
|
||||||
export let extraThin = false
|
|
||||||
export let secondary = false
|
|
||||||
export let outline = false
|
|
||||||
export let disabled = false
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
let focus = false
|
|
||||||
|
|
||||||
const updateValue = e => {
|
|
||||||
value = e.target.value
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFocus(e) {
|
|
||||||
focus = true
|
|
||||||
dispatch("focus", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleBlur(e) {
|
|
||||||
focus = false
|
|
||||||
dispatch("blur", e)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if label}
|
|
||||||
<Label extraSmall grey forAttr={name}>{label}</Label>
|
|
||||||
{/if}
|
|
||||||
<div class="container" class:disabled class:secondary class:outline class:focus>
|
|
||||||
<select
|
|
||||||
{name}
|
|
||||||
class:thin
|
|
||||||
class:extraThin
|
|
||||||
class:secondary
|
|
||||||
{disabled}
|
|
||||||
on:change
|
|
||||||
on:focus={handleFocus}
|
|
||||||
on:blur={handleBlur}
|
|
||||||
bind:value>
|
|
||||||
<slot />
|
|
||||||
</select>
|
|
||||||
<slot name="custom-input" />
|
|
||||||
<input
|
|
||||||
class:thin
|
|
||||||
class:extraThin
|
|
||||||
class:secondary
|
|
||||||
class:disabled
|
|
||||||
{disabled}
|
|
||||||
on:change={updateValue}
|
|
||||||
on:input={updateValue}
|
|
||||||
on:focus={handleFocus}
|
|
||||||
on:blur={e => {
|
|
||||||
updateValue(e)
|
|
||||||
handleBlur(e)
|
|
||||||
}}
|
|
||||||
value={value || ''}
|
|
||||||
type="text" />
|
|
||||||
<div class="pointer editable-pointer">
|
|
||||||
<Icon name="arrowdown" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
position: relative !important;
|
|
||||||
display: block;
|
|
||||||
border-radius: var(--border-radius-s);
|
|
||||||
border: var(--border-transparent);
|
|
||||||
background-color: var(--background);
|
|
||||||
}
|
|
||||||
.container.outline {
|
|
||||||
border: var(--border-dark);
|
|
||||||
}
|
|
||||||
.container.focus {
|
|
||||||
border: var(--border-blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
select {
|
|
||||||
border-radius: var(--border-radius-s);
|
|
||||||
font-size: var(--font-size-m);
|
|
||||||
outline: none;
|
|
||||||
border: none;
|
|
||||||
color: var(--ink);
|
|
||||||
text-align: left;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
display: block !important;
|
|
||||||
width: 100% !important;
|
|
||||||
padding: var(--spacing-m) 2rem var(--spacing-m) var(--spacing-m);
|
|
||||||
appearance: none !important;
|
|
||||||
-webkit-appearance: none !important;
|
|
||||||
-moz-appearance: none !important;
|
|
||||||
align-items: center;
|
|
||||||
white-space: pre;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
input {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: calc(100% - 30px);
|
|
||||||
height: 100%;
|
|
||||||
border: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: var(--spacing-m) 0 var(--spacing-m) var(--spacing-m);
|
|
||||||
}
|
|
||||||
|
|
||||||
select.thin,
|
|
||||||
input.thin {
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
}
|
|
||||||
select.extraThin,
|
|
||||||
input.extraThin {
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
padding: var(--spacing-s) 0 var(--spacing-s) var(--spacing-m);
|
|
||||||
}
|
|
||||||
.secondary {
|
|
||||||
background: var(--grey-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
select:disabled,
|
|
||||||
input:disabled,
|
|
||||||
.disabled {
|
|
||||||
background: var(--grey-4);
|
|
||||||
color: var(--grey-6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.pointer {
|
|
||||||
right: 0 !important;
|
|
||||||
top: 0 !important;
|
|
||||||
bottom: 0 !important;
|
|
||||||
position: absolute !important;
|
|
||||||
pointer-events: none !important;
|
|
||||||
align-items: center !important;
|
|
||||||
display: flex !important;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editable-pointer {
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 0 0 0 1px;
|
|
||||||
border-color: var(--grey-4);
|
|
||||||
padding-left: var(--spacing-xs);
|
|
||||||
}
|
|
||||||
.editable-pointer :global(svg) {
|
|
||||||
margin-right: var(--spacing-xs);
|
|
||||||
fill: var(--ink);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,57 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Select from "./Select.svelte";
|
|
||||||
import DataList from "./DataList.svelte";
|
|
||||||
import Spacer from "../Spacer/Spacer.svelte"
|
|
||||||
|
|
||||||
const options = ["Chocolate", "Vanilla", "Strawberry Cheesecake"];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<DataList name="Test" label="Flavour">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</DataList>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="secondary">
|
|
||||||
<DataList secondary name="Test" label="Flavour">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</DataList>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="outline">
|
|
||||||
<DataList outline name="Test" label="Flavour">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</DataList>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="disabled">
|
|
||||||
<DataList disabled name="Test" label="Flavour">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</DataList>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="thin">
|
|
||||||
<DataList thin name="Test" label="Flavour">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</DataList>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="extraThin">
|
|
||||||
<DataList extraThin name="Test" label="Flavour">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</DataList>
|
|
||||||
</View>
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
<script>
|
||||||
|
import Field from "./Field.svelte"
|
||||||
|
import DatePicker from "./Core/DatePicker.svelte"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = null
|
||||||
|
export let label = null
|
||||||
|
export let labelPosition = "above"
|
||||||
|
export let disabled = false
|
||||||
|
export let error = null
|
||||||
|
export let enableTime = true
|
||||||
|
export let placeholder = null
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = e => {
|
||||||
|
value = e.detail
|
||||||
|
dispatch("change", e.detail)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Field {label} {labelPosition} {disabled} {error}>
|
||||||
|
<DatePicker
|
||||||
|
{error}
|
||||||
|
{disabled}
|
||||||
|
{value}
|
||||||
|
{placeholder}
|
||||||
|
{enableTime}
|
||||||
|
on:change={onChange}
|
||||||
|
/>
|
||||||
|
</Field>
|
|
@ -0,0 +1,32 @@
|
||||||
|
<script>
|
||||||
|
import Field from "./Field.svelte"
|
||||||
|
import CoreDropzone from "./Core/Dropzone.svelte"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = []
|
||||||
|
export let label = null
|
||||||
|
export let labelPosition = "above"
|
||||||
|
export let disabled = false
|
||||||
|
export let error = null
|
||||||
|
export let fileSizeLimit = undefined
|
||||||
|
export let processFiles = undefined
|
||||||
|
export let handleFileTooLarge = undefined
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = e => {
|
||||||
|
value = e.detail
|
||||||
|
dispatch("change", e.detail)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Field {label} {labelPosition} {disabled} {error}>
|
||||||
|
<CoreDropzone
|
||||||
|
{error}
|
||||||
|
{disabled}
|
||||||
|
{value}
|
||||||
|
{fileSizeLimit}
|
||||||
|
{processFiles}
|
||||||
|
{handleFileTooLarge}
|
||||||
|
on:change={onChange}
|
||||||
|
/>
|
||||||
|
</Field>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<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"}>
|
||||||
|
{#if label}
|
||||||
|
<FieldLabel forId={id} {label} position={labelPosition} />
|
||||||
|
{/if}
|
||||||
|
<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,27 @@
|
||||||
|
<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,34 @@
|
||||||
<script>
|
<script>
|
||||||
|
import Field from "./Field.svelte"
|
||||||
|
import TextField from "./Core/TextField.svelte"
|
||||||
import { createEventDispatcher } from "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 value = null
|
||||||
export let label = undefined
|
export let label = null
|
||||||
export let outline = false
|
export let labelPosition = "above"
|
||||||
export let presentation = false
|
export let placeholder = null
|
||||||
export let thin = false
|
export let type = "text"
|
||||||
export let extraThin = false
|
|
||||||
export let large = false
|
|
||||||
export let border = false
|
|
||||||
export let edit = false
|
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let type = undefined
|
export let readonly = false
|
||||||
export let placeholder = ""
|
export let error = null
|
||||||
export let value = ""
|
|
||||||
export let error = false
|
|
||||||
export let validator = () => {}
|
|
||||||
|
|
||||||
// This section handles the edit mode and dispatching of things to the parent when saved
|
const dispatch = createEventDispatcher()
|
||||||
let editMode = false
|
const onChange = e => {
|
||||||
|
value = e.detail
|
||||||
const updateValue = e => {
|
dispatch("change", e.detail)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container">
|
<Field {label} {labelPosition} {disabled} {error}>
|
||||||
{#if label || edit}
|
<TextField
|
||||||
<div class="label-container">
|
{error}
|
||||||
{#if label}
|
{disabled}
|
||||||
<Label extraSmall grey forAttr={name}>{label}</Label>
|
{readonly}
|
||||||
{/if}
|
{value}
|
||||||
{#if edit}
|
{placeholder}
|
||||||
<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}
|
|
||||||
{type}
|
{type}
|
||||||
{name}
|
on:change={onChange}
|
||||||
{placeholder} />
|
on:click
|
||||||
{#if error}
|
on:input
|
||||||
<div class="error">{error}</div>
|
/>
|
||||||
{/if}
|
</Field>
|
||||||
</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>
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Input from "./Input.svelte";
|
|
||||||
import Button from "../Button/Button.svelte";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<Input placeholder="Enter your name" label="Name" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="presentation">
|
|
||||||
<Input presentation placeholder="Enter your name" label="Name" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="outline">
|
|
||||||
<Input outline placeholder="Enter your name" label="Name" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="disabled">
|
|
||||||
<Input disabled placeholder="Enter your name" label="Name" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="disabled with value">
|
|
||||||
<Input value="Some text" disabled placeholder="Enter your name" label="Name" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="thin">
|
|
||||||
<Input thin placeholder="Enter your name" label="Name" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="extraThin">
|
|
||||||
<Input extraThin placeholder="Enter your name" label="Name" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="large">
|
|
||||||
<Input large placeholder="Enter your name" label="Name" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="border">
|
|
||||||
<Input border presentation placeholder="Enter your name" label="Name" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
|
|
||||||
<View name="number">
|
|
||||||
<Input type="number" placeholder="Enter your age" label="Age" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="with edit buttons">
|
|
||||||
<Input
|
|
||||||
thin
|
|
||||||
edit
|
|
||||||
placeholder="Enter your name"
|
|
||||||
label="Name"
|
|
||||||
on:save={console.log} />
|
|
||||||
</View>
|
|
||||||
<View name="with error message">
|
|
||||||
<Input
|
|
||||||
placeholder="Enter your name"
|
|
||||||
label="Name"
|
|
||||||
error="This is an error message!"
|
|
||||||
on:save={console.log} />
|
|
||||||
</View>
|
|
|
@ -1,324 +1,36 @@
|
||||||
<script>
|
<script>
|
||||||
import Portal from "svelte-portal"
|
|
||||||
import { afterUpdate } from "svelte"
|
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import { fly } from "svelte/transition"
|
import Multiselect from "./Core/Multiselect.svelte"
|
||||||
import Label from "../Styleguide/Label.svelte"
|
import Field from "./Field.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 positionDropdown from "../Actions/position_dropdown"
|
|
||||||
import clickOutside from "../Actions/click_outside"
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
export let value = []
|
export let value = []
|
||||||
export let label = undefined
|
export let label = null
|
||||||
export let align = "left"
|
|
||||||
export let secondary = false
|
|
||||||
export let outline = false
|
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let placeholder = undefined
|
export let readonly = false
|
||||||
export let extraThin = 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
|
||||||
|
|
||||||
let options = []
|
const dispatch = createEventDispatcher()
|
||||||
let optionsVisible = false
|
const onChange = e => {
|
||||||
let slot
|
value = e.detail
|
||||||
let anchor
|
dispatch("change", e.detail)
|
||||||
$: 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if label}
|
<Field {label} {labelPosition} {disabled} {error}>
|
||||||
<Label extraSmall grey>{label}</Label>
|
<Multiselect
|
||||||
{/if}
|
{error}
|
||||||
<div class="multiselect" bind:this={anchor}>
|
{disabled}
|
||||||
<div class="tokens-wrapper">
|
{value}
|
||||||
<div
|
{options}
|
||||||
class="tokens"
|
{placeholder}
|
||||||
class:outline
|
{getOptionLabel}
|
||||||
class:disabled
|
{getOptionValue}
|
||||||
class:secondary
|
on:change={onChange}
|
||||||
class:extraThin
|
on:click
|
||||||
class:optionsVisible
|
/>
|
||||||
on:click|self={handleClick}
|
</Field>
|
||||||
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>
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Multiselect from "./Multiselect.svelte";
|
|
||||||
|
|
||||||
const options = ["Red", "Blue", "Yellow", "Green", "Pink", "Very long color name to show text wrapping"];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<Multiselect name="Test" label="Colours" placeholder="Choose some colours">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Multiselect>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="right aligned">
|
|
||||||
<div class="max-width">
|
|
||||||
<Multiselect align="right" name="Test" label="Colours" placeholder="Choose some colours">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Multiselect>
|
|
||||||
</div>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="secondary">
|
|
||||||
<Multiselect name="Test" label="Colours" secondary placeholder="Choose some colours">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Multiselect>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="outline">
|
|
||||||
<Multiselect name="Test" label="Colours" outline placeholder="Choose some colours">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Multiselect>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="disabled">
|
|
||||||
<Multiselect name="Test" label="Colours" disabled placeholder="Choose some colours">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Multiselect>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="extraThin">
|
|
||||||
<Multiselect name="Test" label="Colours" extraThin placeholder="Choose some colours">
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Multiselect>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.max-width {
|
|
||||||
align-self: flex-end;
|
|
||||||
max-width: 150px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,140 +0,0 @@
|
||||||
<script>
|
|
||||||
import { createEventDispatcher } from "svelte"
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
export let value
|
|
||||||
export let group
|
|
||||||
export let name
|
|
||||||
export let disabled = false
|
|
||||||
|
|
||||||
function handleChange() {
|
|
||||||
if (disabled) return
|
|
||||||
group = value
|
|
||||||
dispatch("change", group)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<input
|
|
||||||
{disabled}
|
|
||||||
on:change={handleChange}
|
|
||||||
{value}
|
|
||||||
bind:group
|
|
||||||
type="radio"
|
|
||||||
{name}
|
|
||||||
class="checkbox"
|
|
||||||
id={value} />
|
|
||||||
<div class="checkbox-container" on:click={handleChange}>
|
|
||||||
<div class:disabled class="check-div" class:checked={group === value}>
|
|
||||||
<div class="tick_mark" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
gap: var(--spacing-s);
|
|
||||||
}
|
|
||||||
.checkbox-container {
|
|
||||||
position: relative;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-div {
|
|
||||||
position: relative;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 0.2s ease transform, 0.2s ease background-color,
|
|
||||||
0.2s ease box-shadow;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-div:before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background-color: var(--background);
|
|
||||||
transform: translateY(-50%);
|
|
||||||
transition: 0.2s ease width, 0.2s ease height;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-div:active {
|
|
||||||
transform: translateY(-50%) scale(0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tick_mark {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 6px;
|
|
||||||
width: 5px;
|
|
||||||
height: 4px;
|
|
||||||
margin: 0 auto;
|
|
||||||
transform: rotateZ(-40deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tick_mark:before,
|
|
||||||
.tick_mark:after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
background-color: var(--ink);
|
|
||||||
border-radius: 2px;
|
|
||||||
opacity: 0;
|
|
||||||
transition: 0.2s ease transform, 0.2s ease opacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tick_mark:before {
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 2px;
|
|
||||||
height: 6px;
|
|
||||||
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.23);
|
|
||||||
transform: translateY(-68px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tick_mark:after {
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 12px;
|
|
||||||
height: 2px;
|
|
||||||
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.23);
|
|
||||||
transform: translateX(78px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-div.disabled:active {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checked {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
}
|
|
||||||
.checked.disabled {
|
|
||||||
background-color: var(--grey-5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.checked:before {
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checked .tick_mark:before,
|
|
||||||
.checked .tick_mark:after {
|
|
||||||
transform: translate(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,64 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Radio from "./Radio.svelte";
|
|
||||||
|
|
||||||
let selected = 'Cookies and cream'
|
|
||||||
let selected2 = 'Mint choc chip'
|
|
||||||
|
|
||||||
let menu = [
|
|
||||||
'Cookies and cream',
|
|
||||||
'Mint choc chip',
|
|
||||||
'Raspberry ripple'
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
## Multiple checkboxes
|
|
||||||
Use an array and an each block to use the radio button.
|
|
||||||
```svelte
|
|
||||||
<script>
|
|
||||||
let selected = 'Cookies and cream'
|
|
||||||
let selected2 = 'Cookies and cream'
|
|
||||||
|
|
||||||
let menu = [
|
|
||||||
'Cookies and cream',
|
|
||||||
'Mint choc chip',
|
|
||||||
'Raspberry ripple'
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#each menu as flavour}
|
|
||||||
<Radio name="Ice Cream Flavour" value={flavour} bind:group={selected} label={flavour} showLabel/>
|
|
||||||
{/each}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
<View name="Multiple radio buttons">
|
|
||||||
<div class="container">
|
|
||||||
{#each menu as flavour}
|
|
||||||
<Radio name="Ice Cream Flavour" value={flavour} bind:group={selected}>
|
|
||||||
<label for={flavour}>{flavour}</label>
|
|
||||||
</Radio>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Disabled Radio inputs">
|
|
||||||
<div class="container">
|
|
||||||
{#each menu as flavour}
|
|
||||||
<Radio disabled name="Ice Cream Flavour" value={flavour} bind:group={selected2}>
|
|
||||||
<label for={flavour}>{flavour}</label>
|
|
||||||
</Radio>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
label {
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<script>
|
||||||
|
import Field from "./Field.svelte"
|
||||||
|
import RadioGroup from "./Core/RadioGroup.svelte"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = null
|
||||||
|
export let label = null
|
||||||
|
export let disabled = false
|
||||||
|
export let labelPosition = "above"
|
||||||
|
export let error = null
|
||||||
|
export let options = []
|
||||||
|
export let getOptionLabel = option => extractProperty(option, "label")
|
||||||
|
export let getOptionValue = option => extractProperty(option, "value")
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = e => {
|
||||||
|
value = e.detail
|
||||||
|
dispatch("change", e.detail)
|
||||||
|
}
|
||||||
|
const extractProperty = (value, property) => {
|
||||||
|
if (value && typeof value === "object") {
|
||||||
|
return value[property]
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Field {label} {labelPosition} {disabled} {error}>
|
||||||
|
<RadioGroup
|
||||||
|
{error}
|
||||||
|
{disabled}
|
||||||
|
{value}
|
||||||
|
{options}
|
||||||
|
{getOptionLabel}
|
||||||
|
{getOptionValue}
|
||||||
|
on:change={onChange}
|
||||||
|
/>
|
||||||
|
</Field>
|
|
@ -1,59 +0,0 @@
|
||||||
<script>
|
|
||||||
import * as Quill from "quill"
|
|
||||||
import * as MarkdownIt from "markdown-it"
|
|
||||||
import TurndownService from "turndown"
|
|
||||||
import { onMount } from "svelte"
|
|
||||||
import "quill/dist/quill.snow.css"
|
|
||||||
|
|
||||||
const convertMarkdown = new MarkdownIt()
|
|
||||||
convertMarkdown.set({
|
|
||||||
html: true,
|
|
||||||
})
|
|
||||||
const turndownService = new TurndownService()
|
|
||||||
|
|
||||||
export let value = ""
|
|
||||||
export let options = null
|
|
||||||
export let width = 400
|
|
||||||
|
|
||||||
let quill
|
|
||||||
let container
|
|
||||||
let defaultOptions = {
|
|
||||||
modules: {
|
|
||||||
toolbar: [
|
|
||||||
[{ header: [1, 2, 3, false] }],
|
|
||||||
["bold", "italic", "underline", "strike"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
placeholder: "Type something...",
|
|
||||||
theme: "snow", // or 'bubble'
|
|
||||||
}
|
|
||||||
|
|
||||||
let mergedOptions = { ...defaultOptions, ...options }
|
|
||||||
|
|
||||||
const updateContent = () => {
|
|
||||||
value = turndownService.turndown(quill.container.firstChild.innerHTML)
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
quill = new Quill(container, mergedOptions)
|
|
||||||
if (value)
|
|
||||||
quill.clipboard.dangerouslyPasteHTML(convertMarkdown.render(value + "\n"))
|
|
||||||
|
|
||||||
quill.on("text-change", updateContent)
|
|
||||||
return () => {
|
|
||||||
quill.off("text-change", updateContent)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svelte:head>
|
|
||||||
{#if mergedOptions.theme !== 'snow'}
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="//cdn.quilljs.com/1.3.6/quill.{mergedOptions.theme}.css" />
|
|
||||||
{/if}
|
|
||||||
</svelte:head>
|
|
||||||
|
|
||||||
<div style="width: {width}px">
|
|
||||||
<div bind:this={container} />
|
|
||||||
</div>
|
|
|
@ -1,40 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import RichText from "./RichText.svelte";
|
|
||||||
|
|
||||||
const options = { placeholder: "this is not the default value!" };
|
|
||||||
let value;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
### Rich Text Component
|
|
||||||
|
|
||||||
This component uses the QuillJS library to add Rich Text editing functionality.
|
|
||||||
|
|
||||||
It exposes a <code>content</code> variable that you can bind to in order to get Markdown out of the component.
|
|
||||||
|
|
||||||
As well as the content you can also pass in an option object that looks like so:
|
|
||||||
|
|
||||||
```js
|
|
||||||
let options = {
|
|
||||||
modules: {
|
|
||||||
toolbar: [
|
|
||||||
[{ header: [1, 2, 3, false] }],
|
|
||||||
['bold', 'italic', 'underline', 'strike']
|
|
||||||
]
|
|
||||||
},
|
|
||||||
placeholder: 'Type something...',
|
|
||||||
theme: 'snow'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<RichText bind:value />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="passing in Markdown">
|
|
||||||
<RichText value="# This is an h1 heading!" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="passing in custom options">
|
|
||||||
<RichText {options} />
|
|
||||||
</View>
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<script>
|
||||||
|
import Field from "./Field.svelte"
|
||||||
|
import Search from "./Core/Search.svelte"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = null
|
||||||
|
export let label = null
|
||||||
|
export let labelPosition = "above"
|
||||||
|
export let placeholder = null
|
||||||
|
export let disabled = false
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = e => {
|
||||||
|
value = e.detail
|
||||||
|
dispatch("change", e.detail)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Field {label} {labelPosition} {disabled}>
|
||||||
|
<Search
|
||||||
|
{disabled}
|
||||||
|
{value}
|
||||||
|
{placeholder}
|
||||||
|
on:change={onChange}
|
||||||
|
on:click
|
||||||
|
on:input
|
||||||
|
/>
|
||||||
|
</Field>
|
|
@ -1,95 +1,43 @@
|
||||||
<script>
|
<script>
|
||||||
import Icon from "../Icons/Icon.svelte"
|
import Field from "./Field.svelte"
|
||||||
import Label from "../Styleguide/Label.svelte"
|
import Select from "./Core/Select.svelte"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
export let value = ""
|
export let value = null
|
||||||
export let name = undefined
|
|
||||||
export let label = undefined
|
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 disabled = false
|
||||||
|
export let readonly = false
|
||||||
|
export let labelPosition = "above"
|
||||||
|
export let error = null
|
||||||
|
export let placeholder = "Choose an option"
|
||||||
|
export let options = []
|
||||||
|
export let getOptionLabel = option => extractProperty(option, "label")
|
||||||
|
export let getOptionValue = option => extractProperty(option, "value")
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = e => {
|
||||||
|
value = e.detail
|
||||||
|
dispatch("change", e.detail)
|
||||||
|
}
|
||||||
|
const extractProperty = (value, property) => {
|
||||||
|
if (value && typeof value === "object") {
|
||||||
|
return value[property]
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<Field {label} {labelPosition} {disabled} {error}>
|
||||||
{#if label}
|
<Select
|
||||||
<Label extraSmall grey forAttr={name}>{label}</Label>
|
{error}
|
||||||
{/if}
|
{disabled}
|
||||||
<div class="relative">
|
{readonly}
|
||||||
<select
|
{value}
|
||||||
{name}
|
{options}
|
||||||
class:thin
|
{placeholder}
|
||||||
class:extraThin
|
{getOptionLabel}
|
||||||
class:secondary
|
{getOptionValue}
|
||||||
class:outline
|
on:change={onChange}
|
||||||
{disabled}
|
on:click
|
||||||
on:change
|
/>
|
||||||
bind:value>
|
</Field>
|
||||||
<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>
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Select from "./Select.svelte";
|
|
||||||
import Spacer from "../Spacer/Spacer.svelte"
|
|
||||||
|
|
||||||
const options = ["Chocolate", "Vanilla", "Strawberry Cheesecake"];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<Select name="Test" label="Flavour">
|
|
||||||
<option value="">Choose an option</option>
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Select>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="secondary">
|
|
||||||
<Select secondary name="Test" label="Flavour">
|
|
||||||
<option value="">Choose an option</option>
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Select>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="outline">
|
|
||||||
<Select outline name="Test" label="Flavour">
|
|
||||||
<option value="">Choose an option</option>
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Select>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="disabled">
|
|
||||||
<Select disabled name="Test" label="Flavour">
|
|
||||||
<option value="">Choose an option</option>
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Select>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="thin">
|
|
||||||
<Select thin name="Test" label="Flavour">
|
|
||||||
<option value="">Choose an option</option>
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Select>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="extraThin">
|
|
||||||
<Select extraThin name="Test" label="Flavour">
|
|
||||||
<option value="">Choose an option</option>
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Select>
|
|
||||||
</View>
|
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
<script>
|
|
||||||
import Label from "../Styleguide/Label.svelte"
|
|
||||||
|
|
||||||
export let label
|
|
||||||
export let min = 0
|
|
||||||
export let max = 100
|
|
||||||
export let step = 1
|
|
||||||
export let value
|
|
||||||
export let showValue = false
|
|
||||||
export let showRange = false
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{#if label}
|
|
||||||
<Label extraSmall grey>
|
|
||||||
{label}
|
|
||||||
{#if showValue && value != null}({value}){/if}
|
|
||||||
</Label>
|
|
||||||
{/if}
|
|
||||||
<div class="container">
|
|
||||||
{#if showRange && min != null}<span>{min}</span>{/if}
|
|
||||||
<input type="range" bind:value {min} {max} {step} />
|
|
||||||
{#if showRange && max != null}<span>{max}</span>{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--spacing-s);
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
color: var(--grey-5);
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="range"] {
|
|
||||||
width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
background-color: transparent;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
input[type="range"]:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
input[type="range"]::-webkit-slider-runnable-track {
|
|
||||||
background: var(--grey-4);
|
|
||||||
border-radius: 9px;
|
|
||||||
width: 100%;
|
|
||||||
height: 18px;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0 2px;
|
|
||||||
}
|
|
||||||
input[type="range"]::-webkit-slider-thumb {
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
background: white;
|
|
||||||
border-radius: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
border: none;
|
|
||||||
margin-top: 2px;
|
|
||||||
}
|
|
||||||
input[type="range"]::-moz-range-track {
|
|
||||||
background: var(--grey-4);
|
|
||||||
border-radius: 9px;
|
|
||||||
width: 100%;
|
|
||||||
height: 18px;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0 2px;
|
|
||||||
}
|
|
||||||
input[type="range"]::-moz-range-thumb {
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
background: white;
|
|
||||||
border-radius: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,26 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Slider from "./Slider.svelte";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<Slider label=Quantity value="50" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="show value">
|
|
||||||
<Slider label="Quantity" value="50" showValue />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="show range">
|
|
||||||
<Slider label="Quantity" value="25" showValue showRange min="0" max="100" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="custom min and max">
|
|
||||||
<Slider label="Quantity" value="350" showValue showRange min="50" max="500" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="custom step">
|
|
||||||
<Slider label="Quantity" value="25" step="25" showValue showRange min="0" max="100" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
|
|
|
@ -1,132 +1,30 @@
|
||||||
<script>
|
<script>
|
||||||
|
import Field from "./Field.svelte"
|
||||||
|
import TextArea from "./Core/TextArea.svelte"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import Button from "../Button/Button.svelte"
|
|
||||||
import Label from "../Styleguide/Label.svelte"
|
export let value = null
|
||||||
import text_area_resize from "../Actions/autoresize_textarea.js"
|
export let label = null
|
||||||
|
export let labelPosition = "above"
|
||||||
|
export let placeholder = null
|
||||||
|
export let disabled = false
|
||||||
|
export let error = null
|
||||||
|
export let getCaretPosition = null
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = e => {
|
||||||
export let name = false
|
value = e.detail
|
||||||
export let label = false
|
dispatch("change", e.detail)
|
||||||
export let thin = false
|
|
||||||
export let extraThin = false
|
|
||||||
export let edit = false
|
|
||||||
export let disabled = false
|
|
||||||
export let placeholder
|
|
||||||
export let validator = () => {}
|
|
||||||
export let value = ""
|
|
||||||
export const getCaretPosition = () => {
|
|
||||||
return { start: textarea.selectionStart, end: textarea.selectionEnd }
|
|
||||||
}
|
|
||||||
|
|
||||||
let textarea
|
|
||||||
|
|
||||||
// This section handles the edit mode and dispatching of things to the parent when saved
|
|
||||||
let editMode = false
|
|
||||||
|
|
||||||
const save = () => {
|
|
||||||
editMode = false
|
|
||||||
dispatch("save", value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const enableEdit = () => {
|
|
||||||
editMode = true
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container">
|
<Field {label} {labelPosition} {disabled} {error}>
|
||||||
{#if label || edit}
|
<TextArea
|
||||||
<div class="label-container">
|
bind:getCaretPosition
|
||||||
{#if label}
|
{error}
|
||||||
<Label extraSmall grey forAttr={name}>{label}</Label>
|
{disabled}
|
||||||
{/if}
|
{value}
|
||||||
{#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}
|
|
||||||
<textarea
|
|
||||||
class:thin
|
|
||||||
class:extraThin
|
|
||||||
bind:value
|
|
||||||
bind:this={textarea}
|
|
||||||
on:change
|
|
||||||
disabled={disabled || (edit && !editMode)}
|
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{name}
|
on:change={onChange}
|
||||||
use:text_area_resize />
|
/>
|
||||||
</div>
|
</Field>
|
||||||
|
|
||||||
<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);
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
min-width: 0;
|
|
||||||
color: var(--ink);
|
|
||||||
font-size: var(--font-size-s);
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
border: none;
|
|
||||||
border-radius: var(--border-radius-s);
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
padding: var(--spacing-m);
|
|
||||||
margin: 0;
|
|
||||||
border: var(--border-transparent);
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
textarea::placeholder {
|
|
||||||
color: var(--grey-6);
|
|
||||||
}
|
|
||||||
textarea.thin {
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
}
|
|
||||||
textarea.extraThin {
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
padding: var(--spacing-s) var(--spacing-m);
|
|
||||||
}
|
|
||||||
textarea:focus {
|
|
||||||
border: var(--border-blue);
|
|
||||||
}
|
|
||||||
textarea:disabled {
|
|
||||||
background: var(--grey-4);
|
|
||||||
}
|
|
||||||
textarea:disabled {
|
|
||||||
background: var(--grey-4);
|
|
||||||
}
|
|
||||||
textarea:disabled::placeholder {
|
|
||||||
color: var(--grey-6);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import TextArea from "./TextArea.svelte";
|
|
||||||
|
|
||||||
import Button from "../Button/Button.svelte";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<TextArea placeholder="Enter your email text" label="Email Body" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="disabled">
|
|
||||||
<TextArea disabled placeholder="Enter your email text" label="Email Body" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="no label">
|
|
||||||
<TextArea placeholder="Enter your email text" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="thin">
|
|
||||||
<TextArea thin placeholder="Enter your email text" label="Email Body" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="extraThin">
|
|
||||||
<TextArea extraThin placeholder="Enter your email text" label="Email Body" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="with buttons">
|
|
||||||
<TextArea edit placeholder="Enter your email text" label="Email Body" />
|
|
||||||
</View>
|
|
|
@ -1,110 +1,22 @@
|
||||||
<script>
|
<script>
|
||||||
export let name = undefined
|
import Field from "./Field.svelte"
|
||||||
export let text = ""
|
import Switch from "./Core/Switch.svelte"
|
||||||
export let checked = false
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let value = null
|
||||||
|
export let label = null
|
||||||
|
export let labelPosition = "above"
|
||||||
|
export let text = null
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let screenreader = true
|
export let error = null
|
||||||
export let thin = false
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onChange = e => {
|
||||||
|
value = e.detail
|
||||||
|
dispatch("change", e.detail)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label for={name} class="container">
|
<Field {label} {labelPosition} {disabled} {error}>
|
||||||
<div class="toggle">
|
<Switch {error} {disabled} {text} {value} on:change={onChange} />
|
||||||
<input
|
</Field>
|
||||||
id={name}
|
|
||||||
{name}
|
|
||||||
type="checkbox"
|
|
||||||
class:screenreader
|
|
||||||
{disabled}
|
|
||||||
bind:checked
|
|
||||||
on:change />
|
|
||||||
<div class="track">
|
|
||||||
<div class="thumb" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{#if text}<span class="text" class:thin>{text}</span>{/if}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--spacing-s);
|
|
||||||
}
|
|
||||||
.container:disabled {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
align-self: center;
|
|
||||||
cursor: pointer;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.track {
|
|
||||||
width: 32px;
|
|
||||||
height: 18px;
|
|
||||||
background-color: var(--grey-4);
|
|
||||||
border-radius: 9px;
|
|
||||||
transition-delay: 0.12s;
|
|
||||||
transition-duration: 0.2s;
|
|
||||||
transition-property: background;
|
|
||||||
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thumb {
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
transition-duration: 0.28s;
|
|
||||||
transition-property: all;
|
|
||||||
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
|
||||||
top: 2px;
|
|
||||||
left: 2px;
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
background-color: white;
|
|
||||||
border-radius: var(--border-radius-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="checkbox"]:checked ~ .track .thumb {
|
|
||||||
transform: translateX(14px);
|
|
||||||
}
|
|
||||||
input[type="checkbox"]:checked ~ .track {
|
|
||||||
background-color: var(--blue);
|
|
||||||
}
|
|
||||||
input[type="checkbox"]:disabled ~ .track {
|
|
||||||
background-color: var(--grey-4);
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
input[type="checkbox"]:disabled ~ .track .thumb {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.screenreader {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
padding: 0;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0, 0, 0, 0);
|
|
||||||
white-space: nowrap;
|
|
||||||
border-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
font-size: var(--font-size-s);
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
.text.thin {
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Toggle from "./Toggle.svelte";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<Toggle />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="checked with text">
|
|
||||||
<Toggle text="Display on mobile?" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="thin">
|
|
||||||
<Toggle text="Display on mobile?" thin />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="disabled">
|
|
||||||
<Toggle disabled={true} />
|
|
||||||
</View>
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<script context="module">
|
||||||
|
export const directions = ["n", "ne", "e", "se", "s", "sw", "w", "nw"]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export let direction = "n"
|
||||||
|
export let name = "Add"
|
||||||
|
export let hidden = false
|
||||||
|
export let size = "M"
|
||||||
|
export let hoverable = false
|
||||||
|
export let disabled = false
|
||||||
|
|
||||||
|
$: rotation = directions.indexOf(direction) * 45
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
on:click
|
||||||
|
class:hoverable
|
||||||
|
class:disabled
|
||||||
|
class="spectrum-Icon spectrum-Icon--size{size}"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden={hidden}
|
||||||
|
aria-label={name}
|
||||||
|
style={`transform: rotate(${rotation}deg)`}
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-icon-18-{name}" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
svg.hoverable {
|
||||||
|
pointer-events: all;
|
||||||
|
transition: color var(--spectrum-global-animation-duration-100, 130ms);
|
||||||
|
}
|
||||||
|
svg.hoverable:hover {
|
||||||
|
color: var(--spectrum-alias-icon-color-selected);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg.disabled {
|
||||||
|
color: var(--spectrum-global-color-gray-500) !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,14 +0,0 @@
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="24"
|
|
||||||
height="24">
|
|
||||||
<path fill="none" d="M0 0h24v24H0z" />
|
|
||||||
<path
|
|
||||||
d="M14.121 10.48a1 1 0 0 0-1.414 0l-.707.706a2 2 0 1
|
|
||||||
1-2.828-2.828l5.63-5.632a6.5 6.5 0 0 1 6.377 10.568l-2.108
|
|
||||||
2.135-4.95-4.95zM3.161 4.468a6.503 6.503 0 0 1 8.009-.938L7.757 6.944a4 4 0
|
|
||||||
0 0 5.513 5.794l.144-.137 4.243 4.242-4.243 4.243a2 2 0 0 1-2.828 0L3.16
|
|
||||||
13.66a6.5 6.5 0 0 1 0-9.192z"
|
|
||||||
fill="rgba(128,129,146,1)" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 493 B |
|
@ -1,34 +0,0 @@
|
||||||
<script context="module">
|
|
||||||
import pathsByName from "./icon-paths"
|
|
||||||
export const iconOptions = Object.keys(pathsByName)
|
|
||||||
export const directions = ["n", "ne", "e", "se", "s", "sw", "w", "nw"]
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export let name = "arrow"
|
|
||||||
export let direction = "n"
|
|
||||||
|
|
||||||
$: paths = pathsByName[name] || []
|
|
||||||
$: rotation = directions.indexOf(direction) * 45
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svg
|
|
||||||
class="c"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill-rule="evenodd"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
style={`transform: rotate(${rotation}deg)`}>
|
|
||||||
{#each paths as path}
|
|
||||||
<path d={path} />
|
|
||||||
{/each}
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.c {
|
|
||||||
width: 1.25em;
|
|
||||||
height: 1.25em;
|
|
||||||
fill: currentColor;
|
|
||||||
overflow: visible;
|
|
||||||
margin-right: var(--spacing-xs);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,109 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Icon from "./Icon.svelte";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="add icon">
|
|
||||||
<Icon name="add" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Add Row icon">
|
|
||||||
<Icon name="addrow" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Add Column icon">
|
|
||||||
<Icon name="addcolumn" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="View icon">
|
|
||||||
<Icon name="view" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Table icon">
|
|
||||||
<Icon name="table" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Edit icon">
|
|
||||||
<Icon name="edit" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Delete icon">
|
|
||||||
<Icon name="delete" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Close icon">
|
|
||||||
<Icon name="close" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Arrow Up icon">
|
|
||||||
<Icon name="arrowup" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Arrow Right icon">
|
|
||||||
<Icon name="arrowright" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Arrow Down icon">
|
|
||||||
<Icon name="arrowdown" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Arrow Left icon">
|
|
||||||
<Icon name="arrowleft" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Search icon">
|
|
||||||
<Icon name="search" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Preview icon">
|
|
||||||
<Icon name="preview" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Settings icon">
|
|
||||||
<Icon name="settings" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Add User icon">
|
|
||||||
<Icon name="adduser" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Plugin icon">
|
|
||||||
<Icon name="plugin" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Help icon">
|
|
||||||
<Icon name="help" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Sort Ascending icon">
|
|
||||||
<Icon name="sortascending" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Sort Descending icon">
|
|
||||||
<Icon name="sortdescending" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Calculate icon">
|
|
||||||
<Icon name="calculate" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Filter icon">
|
|
||||||
<Icon name="filter" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Add Fill">
|
|
||||||
<Icon name="addfill" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Group">
|
|
||||||
<Icon name="group" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Lightning">
|
|
||||||
<Icon name="lightning" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View name="Download">
|
|
||||||
<Icon name="download" />
|
|
||||||
</View>
|
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
export default {
|
|
||||||
arrow: [
|
|
||||||
"M0.200275 13.2782C0.200275 12.4153 0.89983 11.7157 1.76278 11.7157H23.6378C24.5007 11.7157 25.2003 12.4153 25.2003 13.2782C25.2003 14.1411 24.5007 14.8407 23.6378 14.8407H1.76278C0.89983 14.8407 0.200275 14.1411 0.200275 13.2782Z",
|
|
||||||
"M11.5954 1.23584C12.2056 0.62565 13.1949 0.62565 13.8051 1.23584L24.7426 12.1733C25.3528 12.7835 25.3528 13.7729 24.7426 14.3831L13.8051 25.3206C13.1949 25.9307 12.2056 25.9307 11.5954 25.3206C10.9852 24.7104 10.9852 23.721 11.5954 23.1108L21.4281 13.2782L11.5954 3.44555C10.9852 2.83536 10.9852 1.84604 11.5954 1.23584Z",
|
|
||||||
],
|
|
||||||
check: [
|
|
||||||
"M24.3522 3.64786C23.4883 2.78405 22.0878 2.78405 21.224 3.64786L8.64198 16.2299L3.77601 11.3639C2.9122 10.5001 1.51168 10.5001 0.647861 11.3639C-0.215954 12.2277 -0.215954 13.6283 0.647861 14.4921L7.07791 20.9221C7.94172 21.7859 9.34224 21.7859 10.2061 20.9221L24.3522 6.77601L23.6974 6.12128L24.3522 6.77601C25.216 5.9122 25.216 4.51168 24.3522 3.64786L23.6974 4.30259L24.3522 3.64786Z",
|
|
||||||
],
|
|
||||||
coffee: [
|
|
||||||
"M6.69069 1.96879C6.69069 1.36848 6.20405 0.881836 5.60374 0.881836C5.00343 0.881836 4.51678 1.36848 4.51678 1.96879V5.22966C4.51678 5.82997 5.00343 6.31662 5.60374 6.31662C6.20405 6.31662 6.69069 5.82997 6.69069 5.22966V1.96879ZM0.168955 9.57749C0.168955 8.97718 0.655602 8.49053 1.25591 8.49053H18.6472H19.7342C21.1756 8.49053 22.5579 9.06312 23.5771 10.0823C24.5964 11.1016 25.169 12.4839 25.169 13.9253C25.169 15.3667 24.5964 16.7491 23.5771 17.7683C22.5579 18.7875 21.1756 19.3601 19.7342 19.3601C19.7342 20.8015 19.1616 22.1838 18.1424 23.2031C17.1231 24.2223 15.7408 24.7949 14.2994 24.7949H5.60374C4.16234 24.7949 2.77998 24.2223 1.76077 23.2031C0.741547 22.1838 0.168955 20.8015 0.168955 19.3601V9.57749ZM19.7342 17.1862V10.6644C20.599 10.6644 21.4284 11.008 22.04 11.6195C22.6515 12.2311 22.995 13.0605 22.995 13.9253C22.995 14.7901 22.6515 15.6196 22.04 16.2311C21.4284 16.8426 20.599 17.1862 19.7342 17.1862ZM17.5603 10.6644V18.2731V19.3601C17.5603 20.2249 17.2167 21.0543 16.6052 21.6659C15.9936 22.2774 15.1642 22.621 14.2994 22.621H5.60374C4.7389 22.621 3.90949 22.2774 3.29795 21.6659C2.68642 21.0543 2.34287 20.2249 2.34287 19.3601V10.6644H17.5603ZM9.95156 0.881836C10.5519 0.881836 11.0385 1.36848 11.0385 1.96879V5.22966C11.0385 5.82997 10.5519 6.31662 9.95156 6.31662C9.35125 6.31662 8.86461 5.82997 8.86461 5.22966V1.96879C8.86461 1.36848 9.35125 0.881836 9.95156 0.881836ZM15.3863 1.96879C15.3863 1.36848 14.8997 0.881836 14.2994 0.881836C13.6991 0.881836 13.2124 1.36848 13.2124 1.96879V5.22966C13.2124 5.82997 13.6991 6.31662 14.2994 6.31662C14.8997 6.31662 15.3863 5.82997 15.3863 5.22966V1.96879Z",
|
|
||||||
],
|
|
||||||
copy: [
|
|
||||||
"M2.98325 3.58322C3.19636 3.37011 3.48539 3.25039 3.78678 3.25039H14.014C14.3154 3.25039 14.6045 3.37011 14.8176 3.58322C15.0307 3.79633 15.1504 4.08537 15.1504 4.38675V5.52312C15.1504 6.15071 15.6592 6.65948 16.2868 6.65948C16.9144 6.65948 17.4231 6.15071 17.4231 5.52312V4.38675C17.4231 3.4826 17.064 2.61549 16.4246 1.97616C15.7853 1.33683 14.9182 0.977661 14.014 0.977661H3.78678C2.88263 0.977661 2.01551 1.33683 1.37619 1.97616C0.736856 2.61549 0.377686 3.4826 0.377686 4.38675V14.614C0.377686 15.5182 0.736857 16.3853 1.37619 17.0246C2.01551 17.6639 2.88263 18.0231 3.78678 18.0231H4.92314C5.55074 18.0231 6.0595 17.5143 6.0595 16.8868C6.0595 16.2592 5.55074 15.7504 4.92314 15.7504H3.78678C3.48539 15.7504 3.19636 15.6307 2.98325 15.4176C2.77014 15.2044 2.65041 14.9154 2.65041 14.614V4.38675C2.65041 4.08537 2.77014 3.79633 2.98325 3.58322ZM10.605 12.3413C10.605 11.7137 11.1137 11.2049 11.7413 11.2049H21.9686C22.5962 11.2049 23.105 11.7137 23.105 12.3413V22.5686C23.105 23.1962 22.5962 23.7049 21.9686 23.7049H11.7413C11.1137 23.7049 10.605 23.1962 10.605 22.5686V12.3413ZM11.7413 8.93221C9.85853 8.93221 8.33223 10.4585 8.33223 12.3413V22.5686C8.33223 24.4514 9.85853 25.9777 11.7413 25.9777H21.9686C23.8514 25.9777 25.3777 24.4514 25.3777 22.5686V12.3413C25.3777 10.4585 23.8514 8.93221 21.9686 8.93221H11.7413Z",
|
|
||||||
],
|
|
||||||
downloadalt: [
|
|
||||||
"M2.21191 15.4277C2.90227 15.4277 3.46191 15.9874 3.46191 16.6777V21.6777C3.46191 22.0093 3.59361 22.3272 3.82803 22.5616C4.06245 22.796 4.38039 22.9277 4.71191 22.9277H22.2119C22.5434 22.9277 22.8614 22.796 23.0958 22.5616C23.3302 22.3272 23.4619 22.0093 23.4619 21.6777V16.6777C23.4619 15.9874 24.0216 15.4277 24.7119 15.4277C25.4023 15.4277 25.9619 15.9874 25.9619 16.6777V21.6777C25.9619 22.6723 25.5668 23.6261 24.8636 24.3294C24.1603 25.0326 23.2065 25.4277 22.2119 25.4277H4.71191C3.71735 25.4277 2.76352 25.0326 2.06026 24.3294C1.357 23.6261 0.961914 22.6723 0.961914 21.6777V16.6777C0.961914 15.9874 1.52156 15.4277 2.21191 15.4277Z",
|
|
||||||
"M6.32803 9.54385C6.81619 9.0557 7.60764 9.0557 8.0958 9.54385L13.4619 14.91L18.828 9.54385C19.3162 9.0557 20.1076 9.0557 20.5958 9.54385C21.084 10.032 21.084 10.8235 20.5958 11.3116L14.3458 17.5616C13.8576 18.0498 13.0662 18.0498 12.578 17.5616L6.32803 11.3116C5.83988 10.8235 5.83988 10.032 6.32803 9.54385Z",
|
|
||||||
"M13.4619 0.427734C14.1523 0.427734 14.7119 0.987378 14.7119 1.67773V16.6777C14.7119 17.3681 14.1523 17.9277 13.4619 17.9277C12.7716 17.9277 12.2119 17.3681 12.2119 16.6777V1.67773C12.2119 0.987378 12.7716 0.427734 13.4619 0.427734Z",
|
|
||||||
],
|
|
||||||
external: [
|
|
||||||
"M25.3673 1.28312C25.3077 1.13904 25.22 1.00384 25.1042 0.88591C25.0988 0.88042 25.0933 0.87498 25.0878 0.86959C24.8623 0.648163 24.5532 0.511597 24.2122 0.511597H24.2119H16.7122C16.0218 0.511597 15.4622 1.07124 15.4622 1.7616C15.4622 2.45195 16.0218 3.0116 16.7122 3.0116H21.1944L9.57827 14.6277C9.09012 15.1159 9.09012 15.9073 9.57827 16.3955C10.0664 16.8836 10.8579 16.8836 11.346 16.3955L22.9622 4.77936V9.2616C22.9622 9.95195 23.5218 10.5116 24.2122 10.5116C24.9025 10.5116 25.4622 9.95195 25.4622 9.2616V1.76269C25.4622 1.75848 25.4621 1.75427 25.4621 1.75006C25.4606 1.59108 25.429 1.43233 25.3673 1.28312ZM4.21216 6.7616C3.88064 6.7616 3.5627 6.89329 3.32827 7.12771C3.09385 7.36213 2.96216 7.68008 2.96216 8.0116V21.7616C2.96216 22.0931 3.09385 22.4111 3.32827 22.6455C3.5627 22.8799 3.88064 23.0116 4.21216 23.0116H17.9622C18.2937 23.0116 18.6116 22.8799 18.846 22.6455C19.0805 22.4111 19.2122 22.0931 19.2122 21.7616V14.2616C19.2122 13.5712 19.7718 13.0116 20.4622 13.0116C21.1525 13.0116 21.7122 13.5712 21.7122 14.2616V21.7616C21.7122 22.7562 21.3171 23.71 20.6138 24.4132C19.9105 25.1165 18.9567 25.5116 17.9622 25.5116H4.21216C3.2176 25.5116 2.26377 25.1165 1.56051 24.4132C0.857246 23.71 0.462158 22.7562 0.462158 21.7616V8.0116C0.462158 7.01704 0.857246 6.06321 1.56051 5.35995C2.26377 4.65668 3.2176 4.2616 4.21216 4.2616H11.7122C12.4025 4.2616 12.9622 4.82124 12.9622 5.5116C12.9622 6.20195 12.4025 6.7616 11.7122 6.7616H4.21216Z",
|
|
||||||
],
|
|
||||||
file: [
|
|
||||||
"M4.00045 1.63229C4.63978 0.99296 5.5069 0.633789 6.41104 0.633789H14.3656C14.667 0.633789 14.956 0.753513 15.1691 0.966622L23.1237 8.92117C23.3368 9.13428 23.4565 9.42332 23.4565 9.7247V22.2247C23.4565 23.1288 23.0973 23.996 22.458 24.6353C21.8187 25.2746 20.9516 25.6338 20.0474 25.6338H6.41104C5.5069 25.6338 4.63978 25.2746 4.00045 24.6353C3.36112 23.996 3.00195 23.1288 3.00195 22.2247V4.04288C3.00195 3.13873 3.36112 2.27162 4.00045 1.63229ZM6.41104 2.90652C6.10966 2.90652 5.82062 3.02624 5.60751 3.23935C5.3944 3.45246 5.27468 3.7415 5.27468 4.04288V22.2247C5.27468 22.5261 5.3944 22.8151 5.60751 23.0282C5.82062 23.2413 6.10966 23.3611 6.41104 23.3611H20.0474C20.3488 23.3611 20.6378 23.2413 20.8509 23.0282C21.064 22.8151 21.1838 22.5261 21.1838 22.2247V10.1954L13.8949 2.90652H6.41104Z",
|
|
||||||
"M14.3656 0.633789C14.9932 0.633789 15.502 1.14256 15.502 1.77015V8.58833H22.3202C22.9478 8.58833 23.4565 9.0971 23.4565 9.7247C23.4565 10.3523 22.9478 10.8611 22.3202 10.8611H14.3656C13.738 10.8611 13.2292 10.3523 13.2292 9.7247V1.77015C13.2292 1.14256 13.738 0.633789 14.3656 0.633789Z",
|
|
||||||
],
|
|
||||||
list: [
|
|
||||||
"M0 10.25C0 9.55964 0.559644 9 1.25 9H18.75C19.4404 9 20 9.55964 20 10.25C20 10.9404 19.4404 11.5 18.75 11.5H1.25C0.559644 11.5 0 10.9404 0 10.25Z",
|
|
||||||
"M0 5.25C0 4.55964 0.559644 4 1.25 4H23.75C24.4404 4 25 4.55964 25 5.25C25 5.94036 24.4404 6.5 23.75 6.5H1.25C0.559644 6.5 0 5.94036 0 5.25Z",
|
|
||||||
"M0 15.25C0 14.5596 0.559644 14 1.25 14H23.75C24.4404 14 25 14.5596 25 15.25C25 15.9404 24.4404 16.5 23.75 16.5H1.25C0.559644 16.5 0 15.9404 0 15.25Z",
|
|
||||||
"M0 20.25C0 19.5596 0.559644 19 1.25 19H18.75C19.4404 19 20 19.5596 20 20.25C20 20.9404 19.4404 21.5 18.75 21.5H1.25C0.559644 21.5 0 20.9404 0 20.25Z",
|
|
||||||
],
|
|
||||||
money: [
|
|
||||||
"M13.2917 0C13.867 0 14.3333 0.46637 14.3333 1.04167V23.9583C14.3333 24.5336 13.867 25 13.2917 25C12.7164 25 12.25 24.5336 12.25 23.9583V1.04167C12.25 0.46637 12.7164 0 13.2917 0Z",
|
|
||||||
"M7.37294 5.53956C8.25201 4.66049 9.4443 4.16663 10.6875 4.16663H18.5C19.0753 4.16663 19.5417 4.633 19.5417 5.20829C19.5417 5.78359 19.0753 6.24996 18.5 6.24996H10.6875C9.99683 6.24996 9.33445 6.52433 8.84608 7.0127C8.3577 7.50108 8.08333 8.16346 8.08333 8.85413C8.08333 9.54479 8.3577 10.2072 8.84608 10.6955C9.33445 11.1839 9.99683 11.4583 10.6875 11.4583H15.8958C17.139 11.4583 18.3313 11.9522 19.2104 12.8312C20.0895 13.7103 20.5833 14.9026 20.5833 16.1458C20.5833 17.389 20.0895 18.5813 19.2104 19.4604C18.3313 20.3394 17.139 20.8333 15.8958 20.8333H7.04167C6.46637 20.8333 6 20.3669 6 19.7916C6 19.2163 6.46637 18.75 7.04167 18.75H15.8958C16.5865 18.75 17.2489 18.4756 17.7373 17.9872C18.2256 17.4988 18.5 16.8365 18.5 16.1458C18.5 15.4551 18.2256 14.7927 17.7373 14.3044C17.2489 13.816 16.5865 13.5416 15.8958 13.5416H10.6875C9.4443 13.5416 8.25201 13.0478 7.37294 12.1687C6.49386 11.2896 6 10.0973 6 8.85413C6 7.61092 6.49386 6.41864 7.37294 5.53956Z",
|
|
||||||
],
|
|
||||||
paperclip: [
|
|
||||||
"M17.5359 2.82806C16.6555 2.82806 15.8112 3.17779 15.1886 3.80031L5.02747 13.9615C3.99 14.999 3.40716 16.4061 3.40716 17.8733C3.40716 19.3405 3.99 20.7476 5.02747 21.785C6.06493 22.8225 7.47204 23.4053 8.93924 23.4053C10.4064 23.4053 11.8135 22.8225 12.851 21.785L23.0122 11.6239C23.444 11.1921 24.1441 11.1921 24.5759 11.6239C25.0076 12.0556 25.0076 12.7557 24.5759 13.1875L14.4147 23.3487C12.9625 24.8009 10.9929 25.6167 8.93924 25.6167C6.88555 25.6167 4.91598 24.8009 3.4638 23.3487C2.01162 21.8965 1.1958 19.9269 1.1958 17.8733C1.1958 15.8196 2.01162 13.85 3.4638 12.3978L13.625 2.23665C14.6622 1.19941 16.069 0.616699 17.5359 0.616699C19.0028 0.616699 20.4095 1.19941 21.4468 2.23665C22.484 3.27388 23.0667 4.68068 23.0667 6.14755C23.0667 7.61442 22.484 9.02121 21.4468 10.0584L11.2745 20.2196C10.6523 20.8419 9.80824 21.1915 8.92818 21.1915C8.04812 21.1915 7.20411 20.8419 6.58181 20.2196C5.95952 19.5973 5.60992 18.7533 5.60992 17.8733C5.60992 16.9932 5.95952 16.1492 6.58181 15.5269L15.9695 6.15029C16.4015 5.71875 17.1016 5.71916 17.5331 6.15121C17.9647 6.58326 17.9643 7.28333 17.5322 7.71487L8.14548 17.0906C7.93818 17.2981 7.82127 17.5799 7.82127 17.8733C7.82127 18.1668 7.93789 18.4484 8.14548 18.656C8.35306 18.8636 8.63461 18.9802 8.92818 18.9802C9.22175 18.9802 9.50329 18.8636 9.71088 18.656L19.8831 8.49479C20.5054 7.8723 20.8554 7.02773 20.8554 6.14755C20.8554 5.26716 20.5056 4.42284 19.8831 3.80031C19.2606 3.17779 18.4163 2.82806 17.5359 2.82806Z",
|
|
||||||
],
|
|
||||||
person: [
|
|
||||||
"M3.04927 16.6449C4.23321 15.4462 5.83898 14.7727 7.51333 14.7727H17.6143C19.2887 14.7727 20.8945 15.4462 22.0784 16.6449C23.2623 17.8436 23.9275 19.4695 23.9275 21.1648V23.7216C23.9275 24.4276 23.3622 25 22.6648 25C21.9675 25 21.4022 24.4276 21.4022 23.7216V21.1648C21.4022 20.1476 21.0031 19.1721 20.2928 18.4528C19.5824 17.7336 18.6189 17.3295 17.6143 17.3295H7.51333C6.50872 17.3295 5.54526 17.7336 4.83489 18.4528C4.12453 19.1721 3.72545 20.1476 3.72545 21.1648V23.7216C3.72545 24.4276 3.16015 25 2.46282 25C1.76549 25 1.2002 24.4276 1.2002 23.7216V21.1648C1.2002 19.4695 1.86533 17.8436 3.04927 16.6449Z",
|
|
||||||
"M11.9956 2.5C9.92454 2.5 8.24561 4.17893 8.24561 6.25C8.24561 8.32107 9.92454 10 11.9956 10C14.0667 10 15.7456 8.32107 15.7456 6.25C15.7456 4.17893 14.0667 2.5 11.9956 2.5ZM5.74561 6.25C5.74561 2.79822 8.54383 0 11.9956 0C15.4474 0 18.2456 2.79822 18.2456 6.25C18.2456 9.70178 15.4474 12.5 11.9956 12.5C8.54383 12.5 5.74561 9.70178 5.74561 6.25Z",
|
|
||||||
],
|
|
||||||
refresh: [
|
|
||||||
"M6.97937 3.40529C8.70577 2.45337 10.6948 2.08834 12.6467 2.36521C14.5986 2.64207 16.4076 3.54582 17.8012 4.94028C17.8093 4.94841 17.8176 4.95642 17.8259 4.9643L21.0026 7.95574H17.048C16.4203 7.95574 15.9115 8.4646 15.9115 9.09231C15.9115 9.72002 16.4203 10.2289 17.048 10.2289H23.8643H23.8675C24.0269 10.2289 24.1787 10.196 24.3165 10.1367C24.4544 10.0775 24.5828 9.98985 24.6925 9.874C24.7014 9.86462 24.7102 9.85508 24.7187 9.8454C24.9095 9.62998 25.0041 9.36088 25.004 9.09232C25.004 9.09121 25.004 9.09009 25.004 9.08898V2.27288C25.004 1.64517 24.4952 1.13631 23.8675 1.13631C23.2397 1.13631 22.7309 1.64517 22.7309 2.27288V6.46082L19.3966 3.32095C17.6563 1.58497 15.4 0.45984 12.9659 0.11459C10.526 -0.231487 8.03977 0.224801 5.88178 1.4147C3.72379 2.60459 2.01099 4.46363 1.00148 6.71166C-0.00803095 8.9597 -0.259554 11.4749 0.284811 13.8784C0.829176 16.2818 2.13994 18.4432 4.01957 20.0368C5.89921 21.6305 8.24589 22.5701 10.706 22.714C13.1661 22.8579 15.6063 22.1984 17.6589 20.8347C19.7116 19.4711 21.2654 17.4773 22.0863 15.1538C22.2954 14.5619 21.9851 13.9126 21.3933 13.7035C20.8014 13.4944 20.1521 13.8047 19.943 14.3966C19.2863 16.2554 18.0432 17.8504 16.4011 18.9413C14.759 20.0322 12.8068 20.5599 10.8387 20.4447C8.87066 20.3296 6.99332 19.5779 5.48961 18.303C3.9859 17.0281 2.93729 15.299 2.5018 13.3762C2.06631 11.4535 2.26753 9.44129 3.07513 7.64286C3.88274 5.84443 5.25298 4.35721 6.97937 3.40529Z",
|
|
||||||
],
|
|
||||||
swoop: [
|
|
||||||
"M17.6488 0.406796C17.1064 -0.135599 16.227 -0.135599 15.6846 0.406796C15.1422 0.949191 15.1422 1.82859 15.6846 2.37098L20.258 6.94444H6.94444C5.10266 6.94444 3.33632 7.67609 2.03398 8.97843C0.731644 10.2808 0 12.0471 0 13.8889V23.6111C0 24.3782 0.621827 25 1.38889 25C2.15595 25 2.77778 24.3782 2.77778 23.6111V13.8889C2.77778 12.7838 3.21676 11.724 3.99817 10.9426C4.77957 10.1612 5.83938 9.72222 6.94444 9.72222H20.258L15.6846 14.2957C15.1422 14.8381 15.1422 15.7175 15.6846 16.2599C16.227 16.8023 17.1064 16.8023 17.6488 16.2599L24.5932 9.31543C24.8611 9.04749 24.9967 8.69732 24.9999 8.34616C25 8.34189 25 8.33761 25 8.33333C25 8.32906 25 8.32478 24.9999 8.32051C24.9983 8.13686 24.961 7.96173 24.8946 7.80169C24.8268 7.63788 24.7264 7.4844 24.5932 7.35124L17.6488 0.406796Z",
|
|
||||||
],
|
|
||||||
twitter: [
|
|
||||||
"M21.351 2.5026C20.4177 1.5026 19.0844 0.835938 17.6177 0.835938C14.8177 0.835938 12.4844 3.16927 12.4844 6.1026C12.4844 6.5026 12.551 6.9026 12.6177 7.3026C8.35104 7.1026 4.61771 4.96927 2.08438 1.83594C1.61771 2.63594 1.41771 3.5026 1.41771 4.5026C1.41771 6.3026 2.35104 7.9026 3.68437 8.9026C2.81771 8.9026 2.08437 8.63594 1.35104 8.23594V8.3026C1.35104 10.8359 3.08438 12.9693 5.48438 13.4359C5.08438 13.5693 4.61771 13.6359 4.15104 13.6359C3.81771 13.6359 3.48438 13.6359 3.21771 13.5693C3.88438 15.6359 5.75104 17.1693 8.01771 17.2359C6.28438 18.6359 4.08438 19.5026 1.68438 19.5026C1.28438 19.5026 0.884375 19.5026 0.484375 19.4359C2.75104 20.9026 5.41771 21.7693 8.35104 21.7693C17.751 21.7693 22.951 13.7693 22.951 6.83594V6.16927C23.951 5.43594 24.8177 4.5026 25.4844 3.43594C24.551 3.83594 23.551 4.16927 22.551 4.23594C23.4177 3.5026 24.2177 2.5026 24.6177 1.23594C23.6177 1.83594 22.551 2.3026 21.351 2.5026Z",
|
|
||||||
],
|
|
||||||
add: [
|
|
||||||
"M12.5 2.27273C6.85163 2.27273 2.27273 6.85163 2.27273 12.5C2.27273 18.1484 6.85163 22.7273 12.5 22.7273C18.1484 22.7273 22.7273 18.1484 22.7273 12.5C22.7273 6.85163 18.1484 2.27273 12.5 2.27273ZM0 12.5C0 5.59644 5.59644 0 12.5 0C19.4036 0 25 5.59644 25 12.5C25 19.4036 19.4036 25 12.5 25C5.59644 25 0 19.4036 0 12.5Z",
|
|
||||||
"M12.5 7.29167C13.0753 7.29167 13.5417 7.75804 13.5417 8.33333V16.6667C13.5417 17.242 13.0753 17.7083 12.5 17.7083C11.9247 17.7083 11.4583 17.242 11.4583 16.6667V8.33333C11.4583 7.75804 11.9247 7.29167 12.5 7.29167Z",
|
|
||||||
"M7.29167 12.5C7.29167 11.9247 7.75804 11.4583 8.33333 11.4583H16.6667C17.242 11.4583 17.7083 11.9247 17.7083 12.5C17.7083 13.0753 17.242 13.5417 16.6667 13.5417H8.33333C7.75804 13.5417 7.29167 13.0753 7.29167 12.5Z",
|
|
||||||
],
|
|
||||||
addcolumn: [
|
|
||||||
"M10 3c.552 0 1 .448 1 1v16c0 .552-.448 1-1 1H4c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1h6zM9 5H5v14h4V5zm9 2c2.761 0 5 2.239 5 5s-2.239 5-5 5-5-2.239-5-5 2.239-5 5-5zm1 2h-2v1.999L15 11v2l2-.001V15h2v-2.001L21 13v-2l-2-.001V9z",
|
|
||||||
],
|
|
||||||
addrow: [
|
|
||||||
"M12 13c2.761 0 5 2.239 5 5s-2.239 5-5 5-5-2.239-5-5 2.239-5 5-5zm1 2h-2v1.999L9 17v2l2-.001V21h2v-2.001L15 19v-2l-2-.001V15zm7-12c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1H4c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1h16zM5 5v4h14V5H5z",
|
|
||||||
],
|
|
||||||
view: [
|
|
||||||
"M12 3c5.392 0 9.878 3.88 10.819 9-.94 5.12-5.427 9-10.819 9-5.392 0-9.878-3.88-10.819-9C2.121 6.88 6.608 3 12 3zm0 16a9.005 9.005 0 0 0 8.777-7 9.005 9.005 0 0 0-17.554 0A9.005 9.005 0 0 0 12 19zm0-2.5a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9zm0-2a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z",
|
|
||||||
],
|
|
||||||
table: [
|
|
||||||
"M4 8h16V5H4v3zm10 11v-9h-4v9h4zm2 0h4v-9h-4v9zm-8 0v-9H4v9h4zM3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z",
|
|
||||||
],
|
|
||||||
edit: [
|
|
||||||
"M15.728 9.686l-1.414-1.414L5 17.586V19h1.414l9.314-9.314zm1.414-1.414l1.414-1.414-1.414-1.414-1.414 1.414 1.414 1.414zM7.242 21H3v-4.243L16.435 3.322a1 1 0 0 1 1.414 0l2.829 2.829a1 1 0 0 1 0 1.414L7.243 21z",
|
|
||||||
],
|
|
||||||
delete: [
|
|
||||||
"M17 6h5v2h-2v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V8H2V6h5V3a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v3zm1 2H6v12h12V8zM9 4v2h6V4H9z",
|
|
||||||
],
|
|
||||||
close: [
|
|
||||||
"M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-11.414L9.172 7.757 7.757 9.172 10.586 12l-2.829 2.828 1.415 1.415L12 13.414l2.828 2.829 1.415-1.415L13.414 12l2.829-2.828-1.415-1.415L12 10.586z",
|
|
||||||
],
|
|
||||||
arrowup: ["M12 8l6 6H6z"],
|
|
||||||
arrowdown: ["M12 16l-6-6h12z"],
|
|
||||||
arrowleft: ["M8 12l6-6v12z"],
|
|
||||||
arrowright: ["M16 12l-6 6V6z"],
|
|
||||||
search: [
|
|
||||||
"M18.031 16.617l4.283 4.282-1.415 1.415-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9 9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617zm-2.006-.742A6.977 6.977 0 0 0 18 11c0-3.868-3.133-7-7-7-3.868 0-7 3.132-7 7 0 3.867 3.132 7 7 7a6.977 6.977 0 0 0 4.875-1.975l.15-.15z",
|
|
||||||
],
|
|
||||||
settings: [
|
|
||||||
"M2.132 13.63a9.942 9.942 0 0 1 0-3.26c1.102.026 2.092-.502 2.477-1.431.385-.93.058-2.004-.74-2.763a9.942 9.942 0 0 1 2.306-2.307c.76.798 1.834 1.125 2.764.74.93-.385 1.457-1.376 1.43-2.477a9.942 9.942 0 0 1 3.262 0c-.027 1.102.501 2.092 1.43 2.477.93.385 2.004.058 2.763-.74a9.942 9.942 0 0 1 2.307 2.306c-.798.76-1.125 1.834-.74 2.764.385.93 1.376 1.457 2.477 1.43a9.942 9.942 0 0 1 0 3.262c-1.102-.027-2.092.501-2.477 1.43-.385.93-.058 2.004.74 2.763a9.942 9.942 0 0 1-2.306 2.307c-.76-.798-1.834-1.125-2.764-.74-.93.385-1.457 1.376-1.43 2.477a9.942 9.942 0 0 1-3.262 0c.027-1.102-.501-2.092-1.43-2.477-.93-.385-2.004-.058-2.763.74a9.942 9.942 0 0 1-2.307-2.306c.798-.76 1.125-1.834.74-2.764-.385-.93-1.376-1.457-2.477-1.43zM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z",
|
|
||||||
],
|
|
||||||
preview: [
|
|
||||||
"M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zM10.622 8.415a.4.4 0 0 0-.622.332v6.506a.4.4 0 0 0 .622.332l4.879-3.252a.4.4 0 0 0 0-.666l-4.88-3.252z",
|
|
||||||
],
|
|
||||||
adduser: [
|
|
||||||
"M14 14.252V22H4a8 8 0 0 1 10-7.748zM12 13c-3.315 0-6-2.685-6-6s2.685-6 6-6 6 2.685 6 6-2.685 6-6 6zm6 4v-3h2v3h3v2h-3v3h-2v-3h-3v-2h3z",
|
|
||||||
],
|
|
||||||
plugin: [
|
|
||||||
"M13 18v2h6v2h-6a2 2 0 0 1-2-2v-2H8a4 4 0 0 1-4-4v-4h16v4a4 4 0 0 1-4 4h-3zm3-12h3a1 1 0 0 1 1 1v2H4V7a1 1 0 0 1 1-1h3V2h2v4h4V2h2v4zm-4 8.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2z",
|
|
||||||
],
|
|
||||||
help: [
|
|
||||||
"M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm2-1.645A3.502 3.502 0 0 0 12 6.5a3.501 3.501 0 0 0-3.433 2.813l1.962.393A1.5 1.5 0 1 1 12 11.5a1 1 0 0 0-1 1V14h2v-.645z",
|
|
||||||
],
|
|
||||||
sortdescending: [
|
|
||||||
"M19 3l4 5h-3v12h-2V8h-3l4-5zm-5 15v2H3v-2h11zm0-7v2H3v-2h11zm-2-7v2H3V4h9z",
|
|
||||||
],
|
|
||||||
sortascending: [
|
|
||||||
"M20 4v12h3l-4 5-4-5h3V4h2zm-8 14v2H3v-2h9zm2-7v2H3v-2h11zm0-7v2H3V4h11z",
|
|
||||||
],
|
|
||||||
calculate: [
|
|
||||||
"M4 2h16a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1zm1 2v16h14V4H5zm2 2h10v4H7V6zm0 6h2v2H7v-2zm0 4h2v2H7v-2zm4-4h2v2h-2v-2zm0 4h2v2h-2v-2zm4-4h2v6h-2v-6z",
|
|
||||||
],
|
|
||||||
filter: [
|
|
||||||
"M21 4v2h-1l-5 7.5V22H9v-8.5L4 6H3V4h18zM6.404 6L11 12.894V20h2v-7.106L17.596 6H6.404z",
|
|
||||||
],
|
|
||||||
addfill: [
|
|
||||||
"M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11H7v2h4v4h2v-4h4v-2h-4V7h-2v4z",
|
|
||||||
],
|
|
||||||
group: [
|
|
||||||
"M11 4h10v2H11V4zm0 4h6v2h-6V8zm0 6h10v2H11v-2zm0 4h6v2h-6v-2zM3 4h6v6H3V4zm2 2v2h2V6H5zm-2 8h6v6H3v-6zm2 2v2h2v-2H5z",
|
|
||||||
],
|
|
||||||
download: [
|
|
||||||
"M13 10h5l-6 6-6-6h5V3h2v7zm-9 9h16v-7h2v8a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1v-8h2v7z",
|
|
||||||
],
|
|
||||||
lightning: [
|
|
||||||
"M13 9h8L11 24v-9H4l9-15v9zm-2 2V7.22L7.532 13H13v4.394L17.263 11H11z",
|
|
||||||
],
|
|
||||||
closeline: [
|
|
||||||
"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",
|
|
||||||
],
|
|
||||||
}
|
|
|
@ -20,7 +20,8 @@
|
||||||
class:white
|
class:white
|
||||||
class:grey
|
class:grey
|
||||||
class:black
|
class:black
|
||||||
for={forAttr}>
|
for={forAttr}
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
@ -34,35 +35,27 @@
|
||||||
margin-bottom: var(--spacing-s);
|
margin-bottom: var(--spacing-s);
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.extraSmall {
|
.extraSmall {
|
||||||
font-size: var(--font-size-xs);
|
font-size: var(--font-size-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.small {
|
.small {
|
||||||
font-size: var(--font-size-s);
|
font-size: var(--font-size-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.medium {
|
.medium {
|
||||||
font-size: var(--font-size-m);
|
font-size: var(--font-size-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
.large {
|
.large {
|
||||||
font-size: var(--font-size-l);
|
font-size: var(--font-size-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
.extraLarge {
|
.extraLarge {
|
||||||
font-size: var(--font-size-xl);
|
font-size: var(--font-size-xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.white {
|
.white {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grey {
|
.grey {
|
||||||
color: var(--grey-6);
|
color: var(--grey-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.black {
|
.black {
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
}
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
<script>
|
||||||
|
export let horizontal = false
|
||||||
|
export let paddingX = "M"
|
||||||
|
export let paddingY = "M"
|
||||||
|
export let noPadding = false
|
||||||
|
export let gap = "M"
|
||||||
|
export let noGap = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class:horizontal
|
||||||
|
class="container paddingX-{!noPadding && paddingX} paddingY-{!noPadding &&
|
||||||
|
paddingY} gap-{!noGap && gap}"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
.paddingX-S {
|
||||||
|
padding-left: var(--spacing-s);
|
||||||
|
padding-right: var(--spacing-s);
|
||||||
|
}
|
||||||
|
.paddingX-M {
|
||||||
|
padding-left: var(--spacing-m);
|
||||||
|
padding-right: var(--spacing-m);
|
||||||
|
}
|
||||||
|
.paddingX-L {
|
||||||
|
padding-left: var(--spacing-l);
|
||||||
|
padding-right: var(--spacing-l);
|
||||||
|
}
|
||||||
|
.paddingY-S {
|
||||||
|
padding-top: var(--spacing-s);
|
||||||
|
padding-bottom: var(--spacing-s);
|
||||||
|
}
|
||||||
|
.paddingY-M {
|
||||||
|
padding-top: var(--spacing-m);
|
||||||
|
padding-bottom: var(--spacing-m);
|
||||||
|
}
|
||||||
|
.paddingY-L {
|
||||||
|
padding-top: var(--spacing-l);
|
||||||
|
padding-bottom: var(--spacing-l);
|
||||||
|
}
|
||||||
|
.gap-S {
|
||||||
|
grid-gap: var(--spectrum-alias-grid-gutter-xsmall);
|
||||||
|
}
|
||||||
|
.gap-M {
|
||||||
|
grid-gap: var(--spectrum-alias-grid-gutter-small);
|
||||||
|
}
|
||||||
|
.gap-L {
|
||||||
|
grid-gap: var(--spectrum-alias-grid-gutter-medium);
|
||||||
|
}
|
||||||
|
.horizontal.gap-S :global(*) + :global(*) {
|
||||||
|
margin-left: var(--spectrum-alias-grid-gutter-xsmall);
|
||||||
|
}
|
||||||
|
.horizontal.gap-M :global(*) + :global(*) {
|
||||||
|
margin-left: var(--spectrum-alias-grid-gutter-small);
|
||||||
|
}
|
||||||
|
.horizontal.gap-L :global(*) + :global(*) {
|
||||||
|
margin-left: var(--spectrum-alias-grid-gutter-medium);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/link/dist/index-vars.css"
|
||||||
|
|
||||||
|
export let href = "#"
|
||||||
|
export let size = "M"
|
||||||
|
export let quiet = false
|
||||||
|
export let primary = false
|
||||||
|
export let secondary = false
|
||||||
|
export let overBackground = false
|
||||||
|
export let target
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<a
|
||||||
|
{href}
|
||||||
|
{target}
|
||||||
|
class:spectrum-Link--primary={primary}
|
||||||
|
class:spectrum-Link--secondary={secondary}
|
||||||
|
class:spectrum-Link--overBackground={overBackground}
|
||||||
|
class:spectrum-Link--quiet={quiet}
|
||||||
|
class="spectrum-Link spectrum-Link--size{size}"><slot /></a
|
||||||
|
>
|
|
@ -1,50 +0,0 @@
|
||||||
<script>
|
|
||||||
export let href,
|
|
||||||
icon,
|
|
||||||
title,
|
|
||||||
active = false
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<a {href} target="_blank" class="nav-item" class:active>
|
|
||||||
{#if icon}
|
|
||||||
<span class="nav-item-icon">
|
|
||||||
<svelte:component this={icon} />
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
{#if title}
|
|
||||||
<div class="nav-item-title">{title}</div>
|
|
||||||
{/if}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.nav-item {
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 12px;
|
|
||||||
height: 2rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-radius: var(--border-radius-s);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item:hover {
|
|
||||||
background-color: var(--grey-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item-title {
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
color: var(--ink);
|
|
||||||
font-weight: 400;
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item-icon {
|
|
||||||
color: var(--grey-7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.active {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,19 +0,0 @@
|
||||||
<script>
|
|
||||||
import { View } from "svench";
|
|
||||||
import Home from "./Home.svelte";
|
|
||||||
import Contribution from "../Icons/Contribution.svelte";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="default">
|
|
||||||
<Home
|
|
||||||
href="https://github.com/Budibase/budibase/blob/master/CONTRIBUTING.md"
|
|
||||||
title="Contribute"
|
|
||||||
icon={Contribution} />
|
|
||||||
</View>
|
|
||||||
<View name="active">
|
|
||||||
<Home
|
|
||||||
active
|
|
||||||
href="https://github.com/Budibase/budibase/blob/master/CONTRIBUTING.md"
|
|
||||||
title="Contribute"
|
|
||||||
icon={Contribution} />
|
|
||||||
</View>
|
|
|
@ -1,33 +0,0 @@
|
||||||
<script>
|
|
||||||
import Input from "../Form/Input.svelte"
|
|
||||||
|
|
||||||
export let categories = [
|
|
||||||
{
|
|
||||||
name: "Customers List - Data Row",
|
|
||||||
items: [
|
|
||||||
{ name: "Name", id: "chjaHICHc82h2" },
|
|
||||||
{ name: "Created", id: "chjaHICgr56Hc82h2" },
|
|
||||||
{ name: "Status", id: "chjaHICHc8646462h2" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Home Screen Components",
|
|
||||||
items: [{ name: "Title", id: "chjaHICHc82h2" }],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<Input thin placeholder="Search" />
|
|
||||||
{#each categories as { name, items }}
|
|
||||||
<div class="title">{name}</div>
|
|
||||||
<ul>
|
|
||||||
{#each items as { name, id }}
|
|
||||||
<li>{name}</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<script>
|
|
||||||
import Search from "./Search.svelte";
|
|
||||||
import { View } from "svench";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<View name="Name">
|
|
||||||
<Search />
|
|
||||||
</View>
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
<script>
|
||||||
|
import { createEventDispatcher, getContext } from "svelte"
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const actionMenu = getContext("actionMenu")
|
||||||
|
|
||||||
|
export let dataCy
|
||||||
|
export let icon = undefined
|
||||||
|
export let disabled = undefined
|
||||||
|
export let noClose = false
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
if (actionMenu && !noClose) {
|
||||||
|
actionMenu.hide()
|
||||||
|
}
|
||||||
|
dispatch("click")
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<li
|
||||||
|
data-cy={dataCy}
|
||||||
|
on:click|preventDefault={onClick}
|
||||||
|
class="spectrum-Menu-item"
|
||||||
|
class:is-disabled={disabled}
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
{#if icon}
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Menu-itemIcon"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
aria-label={icon}
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
<span class="spectrum-Menu-itemLabel"><slot /></span>
|
||||||
|
</li>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/menu/dist/index-vars.css"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul class="spectrum-Menu" role="menu">
|
||||||
|
<slot />
|
||||||
|
</ul>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script>
|
||||||
|
import Menu from './Menu.svelte'
|
||||||
|
import Separator from './Separator.svelte'
|
||||||
|
import Section from './Section.svelte'
|
||||||
|
import Item from './Item.svelte'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Menu>
|
||||||
|
<Section heading="Section heading">
|
||||||
|
<Item>Some Item 1</Item>
|
||||||
|
<Item>Some Item 2</Item>
|
||||||
|
<Item>Some Item 3</Item>
|
||||||
|
</Section>
|
||||||
|
<Separator />
|
||||||
|
<Section heading="Section heading">
|
||||||
|
<Item icon="SaveFloppy">Save</Item>
|
||||||
|
<Item disabled icon="DataDownload">Download</Item>
|
||||||
|
</Section>
|
||||||
|
</Menu>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<script>
|
||||||
|
export let heading
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<li role="presentation">
|
||||||
|
<span class="spectrum-Menu-sectionHeading">{heading}</span>
|
||||||
|
<ul class="spectrum-Menu" role="group">
|
||||||
|
<slot />
|
||||||
|
</ul>
|
||||||
|
</li>
|
|
@ -0,0 +1 @@
|
||||||
|
<li class="spectrum-Menu-divider" role="separator" />
|
|
@ -17,7 +17,7 @@
|
||||||
<div on:click={increment}>
|
<div on:click={increment}>
|
||||||
Click me
|
Click me
|
||||||
{remaining}
|
{remaining}
|
||||||
more time{remaining === 1 ? '' : 's'}
|
more time{remaining === 1 ? "" : "s"}
|
||||||
to close this modal!
|
to close this modal!
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher, setContext } from "svelte"
|
import "@spectrum-css/modal/dist/index-vars.css"
|
||||||
|
import "@spectrum-css/underlay/dist/index-vars.css"
|
||||||
|
import { createEventDispatcher, setContext, tick } from "svelte"
|
||||||
import { fade, fly } from "svelte/transition"
|
import { fade, fly } from "svelte/transition"
|
||||||
import Portal from "svelte-portal"
|
import Portal from "svelte-portal"
|
||||||
import Context from "../context"
|
import Context from "../context"
|
||||||
|
|
||||||
|
export let fixed = false
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
let visible = !!fixed
|
||||||
export let padding = true
|
|
||||||
export let width = undefined
|
|
||||||
export let border = true
|
|
||||||
|
|
||||||
let visible = false
|
|
||||||
$: dispatch(visible ? "show" : "hide")
|
$: dispatch(visible ? "show" : "hide")
|
||||||
|
|
||||||
export function show() {
|
export function show() {
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hide() {
|
export function hide() {
|
||||||
if (!visible) {
|
if (!visible || fixed) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
visible = false
|
visible = false
|
||||||
|
@ -32,27 +32,33 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function focusFirstInput(node) {
|
||||||
|
const inputs = node.querySelectorAll("input")
|
||||||
|
if (inputs?.length) {
|
||||||
|
await tick()
|
||||||
|
inputs[0].focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setContext(Context.Modal, { show, hide })
|
setContext(Context.Modal, { show, hide })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:keydown={handleKey} />
|
<svelte:window on:keydown={handleKey} />
|
||||||
|
|
||||||
{#if visible}
|
{#if visible}
|
||||||
<Portal target="body">
|
<Portal target=".modal-container">
|
||||||
<div
|
<div
|
||||||
class="overlay"
|
class="spectrum-Underlay is-open"
|
||||||
on:click|self={hide}
|
transition:fade={{ duration: 200 }}
|
||||||
transition:fade={{ duration: 200 }}>
|
on:mousedown|self={hide}
|
||||||
<div
|
>
|
||||||
class="scroll-wrapper"
|
<div class="modal-wrapper" on:mousedown|self={hide}>
|
||||||
on:click|self={hide}
|
<div class="modal-inner-wrapper" on:mousedown|self={hide}>
|
||||||
transition:fly={{ y: 30, duration: 200 }}>
|
|
||||||
<div class="content-wrapper" on:click|self={hide}>
|
|
||||||
<div
|
<div
|
||||||
class="modal"
|
use:focusFirstInput
|
||||||
class:padding
|
class="spectrum-Modal is-open"
|
||||||
class:border
|
transition:fly={{ y: 30, duration: 200 }}
|
||||||
style={width ? `flex: 0 0 ${width}` : ''}>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,55 +68,42 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.overlay {
|
.spectrum-Underlay {
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: auto;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: rgba(0, 0, 0, 0.25);
|
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
|
overflow: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-wrapper {
|
.modal-wrapper {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
-moz-box-pack: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
|
.modal-inner-wrapper {
|
||||||
.content-wrapper {
|
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
-moz-box-pack: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
width: 0;
|
width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal {
|
.spectrum-Modal {
|
||||||
background-color: var(--background);
|
overflow: visible;
|
||||||
display: grid;
|
max-height: none;
|
||||||
align-items: stretch;
|
margin: 40px 0;
|
||||||
box-shadow: 0 0 4rem 1.5rem rgba(0, 0, 0, 0.15);
|
transform: none;
|
||||||
position: relative;
|
--spectrum-dialog-confirm-border-radius: var(
|
||||||
flex: 0 0 400px;
|
--spectrum-global-dimension-size-100
|
||||||
margin: 2rem 0;
|
);
|
||||||
border-radius: var(--border-radius-m);
|
|
||||||
gap: var(--spacing-xl);
|
|
||||||
}
|
|
||||||
.modal.padding {
|
|
||||||
padding: var(--spacing-xl);
|
|
||||||
}
|
|
||||||
.modal.border {
|
|
||||||
border: var(--border-dark);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher, getContext } from "svelte"
|
import "@spectrum-css/dialog/dist/index-vars.css"
|
||||||
|
import { getContext } from "svelte"
|
||||||
import Button from "../Button/Button.svelte"
|
import Button from "../Button/Button.svelte"
|
||||||
import Icon from "../Icons/Icon.svelte"
|
import Divider from "../Divider/Divider.svelte"
|
||||||
|
import Icon from "../Icon/Icon.svelte"
|
||||||
import Context from "../context"
|
import Context from "../context"
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
export let title = undefined
|
export let title = undefined
|
||||||
|
export let size = "S"
|
||||||
export let cancelText = "Cancel"
|
export let cancelText = "Cancel"
|
||||||
export let confirmText = "Confirm"
|
export let confirmText = "Confirm"
|
||||||
export let showCancelButton = true
|
export let showCancelButton = true
|
||||||
|
@ -27,75 +29,83 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="modal-content">
|
<div
|
||||||
{#if title}
|
class="spectrum-Dialog"
|
||||||
<header>
|
class:spectrum-Dialog--small={size === "S"}
|
||||||
<h5>{title}</h5>
|
class:spectrum-Dialog--medium={size === "M"}
|
||||||
<div class="header-content">
|
class:spectrum-Dialog--large={size === "L"}
|
||||||
<slot name="header" />
|
class:spectrum-Dialog--extraLarge={size === "XL"}
|
||||||
</div>
|
style="position: relative;"
|
||||||
</header>
|
role="dialog"
|
||||||
{/if}
|
tabindex="-1"
|
||||||
<slot />
|
aria-modal="true"
|
||||||
{#if showCancelButton || showConfirmButton}
|
>
|
||||||
<footer>
|
<div class="spectrum-Dialog-grid">
|
||||||
<div class="footer-content">
|
<h1 class="spectrum-Dialog-heading spectrum-Dialog-heading--noHeader">
|
||||||
|
{title}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<Divider size="M" />
|
||||||
|
<!-- 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"
|
||||||
|
>
|
||||||
<slot name="footer" />
|
<slot name="footer" />
|
||||||
</div>
|
|
||||||
<div class="buttons">
|
|
||||||
{#if showCancelButton}
|
{#if showCancelButton}
|
||||||
<Button secondary on:click={hide}>{cancelText}</Button>
|
<Button group secondary on:click={hide}>{cancelText}</Button>
|
||||||
{/if}
|
{/if}
|
||||||
{#if showConfirmButton}
|
{#if showConfirmButton}
|
||||||
<Button
|
<Button
|
||||||
primary
|
group
|
||||||
|
cta
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
disabled={confirmDisabled}
|
disabled={confirmDisabled}
|
||||||
on:click={confirm}>
|
on:click={confirm}
|
||||||
|
>
|
||||||
{confirmText}
|
{confirmText}
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
{/if}
|
||||||
{/if}
|
{#if showCloseIcon}
|
||||||
{#if showCloseIcon}
|
<div class="close-icon" on:click={hide}>
|
||||||
<div class="close-icon" on:click={hide}>
|
<Icon hoverable name="Close" />
|
||||||
<Icon name="closeline" />
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.modal-content {
|
.spectrum-Dialog--extraLarge {
|
||||||
|
width: 1000px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
position: relative;
|
position: relative;
|
||||||
gap: var(--spacing-xl);
|
gap: var(--spacing-xl);
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
.spectrum-Dialog-content {
|
||||||
display: flex;
|
overflow: visible;
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-right: 40px;
|
|
||||||
}
|
}
|
||||||
header h5 {
|
.spectrum-Dialog-heading {
|
||||||
margin: 0;
|
font-family: var(--spectrum-alias-body-text-font-family);
|
||||||
font-weight: 500;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-content {
|
.spectrum-Dialog-buttonGroup {
|
||||||
display: flex;
|
gap: var(--spectrum-global-dimension-static-size-200);
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-icon {
|
.close-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 15px;
|
||||||
right: 0;
|
right: 15px;
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
font-size: var(--font-size-m);
|
font-size: var(--font-size-m);
|
||||||
}
|
}
|
||||||
|
@ -106,27 +116,4 @@
|
||||||
.close-icon :global(svg) {
|
.close-icon :global(svg) {
|
||||||
margin-right: 0;
|
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>
|
</style>
|
||||||
|
|
|
@ -31,7 +31,8 @@
|
||||||
bind:this={modal}
|
bind:this={modal}
|
||||||
confirmText="Submit"
|
confirmText="Submit"
|
||||||
onConfirm={answerQuiz}
|
onConfirm={answerQuiz}
|
||||||
on:show={resetState}>
|
on:show={resetState}
|
||||||
|
>
|
||||||
{#if error}
|
{#if error}
|
||||||
<p class="error">Wrong answer! Try again.</p>
|
<p class="error">Wrong answer! Try again.</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/toast/dist/index-vars.css"
|
||||||
|
import Portal from "svelte-portal"
|
||||||
|
import { flip } from "svelte/animate"
|
||||||
|
import { fly } from "svelte/transition"
|
||||||
|
import { notifications } from "../Stores/notifications"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Portal target=".modal-container">
|
||||||
|
<div class="notifications">
|
||||||
|
{#each $notifications as { type, icon, message, id } (id)}
|
||||||
|
<div
|
||||||
|
animate:flip
|
||||||
|
transition:fly={{ y: -30 }}
|
||||||
|
class="spectrum-Toast spectrum-Toast--{type} notification-offset"
|
||||||
|
>
|
||||||
|
{#if icon}
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
<div class="spectrum-Toast-body">
|
||||||
|
<div class="spectrum-Toast-content">{message}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</Portal>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.notifications {
|
||||||
|
position: fixed;
|
||||||
|
top: 10px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.notification-offset {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,24 +1,27 @@
|
||||||
<script>
|
<script>
|
||||||
|
import "@spectrum-css/popover/dist/index-vars.css"
|
||||||
import Portal from "svelte-portal"
|
import Portal from "svelte-portal"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import positionDropdown from "../Actions/position_dropdown"
|
import positionDropdown from "../Actions/position_dropdown"
|
||||||
import clickOutside from "../Actions/click_outside"
|
import clickOutside from "../Actions/click_outside"
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let anchor
|
export let anchor
|
||||||
export let align = "right"
|
export let align = "right"
|
||||||
let open = null
|
|
||||||
|
|
||||||
export const show = () => {
|
export const show = () => {
|
||||||
|
dispatch("open")
|
||||||
open = true
|
open = true
|
||||||
dispatch("show")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hide = () => {
|
export const hide = () => {
|
||||||
|
dispatch("close")
|
||||||
open = false
|
open = false
|
||||||
dispatch("hide")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let open = null
|
||||||
|
|
||||||
function handleEscape(e) {
|
function handleEscape(e) {
|
||||||
if (open && e.key === "Escape") {
|
if (open && e.key === "Escape") {
|
||||||
hide()
|
hide()
|
||||||
|
@ -30,39 +33,19 @@
|
||||||
<Portal>
|
<Portal>
|
||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class:open
|
|
||||||
use:positionDropdown={{ anchor, align }}
|
use:positionDropdown={{ anchor, align }}
|
||||||
use:clickOutside={hide}
|
use:clickOutside={hide}
|
||||||
on:keydown={handleEscape}
|
on:keydown={handleEscape}
|
||||||
class="menu-container">
|
class="spectrum-Popover is-open"
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</Portal>
|
</Portal>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.menu-container {
|
.spectrum-Popover {
|
||||||
position: fixed;
|
min-width: var(--spectrum-global-dimension-size-2000) !important;
|
||||||
margin-top: var(--spacing-xs);
|
|
||||||
padding: var(--spacing-xl);
|
|
||||||
outline: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
opacity: 0;
|
|
||||||
min-width: 400px;
|
|
||||||
z-index: 2;
|
|
||||||
color: var(--ink);
|
|
||||||
height: fit-content !important;
|
|
||||||
border: var(--border-dark);
|
|
||||||
border-radius: var(--border-radius-m);
|
|
||||||
transform: scale(0);
|
|
||||||
transition: opacity 0.13s linear, transform 0.12s cubic-bezier(0, 0, 0.2, 1);
|
|
||||||
overflow-y: auto;
|
|
||||||
background-color: var(--background);
|
|
||||||
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.open {
|
|
||||||
transform: scale(1);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/progressbar/dist/index-vars.css"
|
||||||
|
import { tweened } from "svelte/motion"
|
||||||
|
import { cubicOut } from "svelte/easing"
|
||||||
|
|
||||||
|
export let value = false
|
||||||
|
export let easing = cubicOut
|
||||||
|
export let duration = 1000
|
||||||
|
export let width = false
|
||||||
|
export let sideLabel = false
|
||||||
|
export let overBackground = false
|
||||||
|
|
||||||
|
export let size = "M"
|
||||||
|
|
||||||
|
const progress = tweened(0, {
|
||||||
|
duration: duration,
|
||||||
|
easing: easing,
|
||||||
|
})
|
||||||
|
|
||||||
|
$: if (value) $progress = value
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class:spectrum-ProgressBar--indeterminate={!value}
|
||||||
|
class:spectrum-ProgressBar--sideLabel={sideLabel}
|
||||||
|
class="spectrum-ProgressBar spectrum-ProgressBar--size{size}"
|
||||||
|
value={$progress}
|
||||||
|
role="progressbar"
|
||||||
|
aria-valuenow={$progress}
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax="100"
|
||||||
|
style={width ? `width: ${width}px;` : ""}
|
||||||
|
>
|
||||||
|
{#if $$slots}
|
||||||
|
<div
|
||||||
|
class="spectrum-FieldLabel spectrum-ProgressBar-label spectrum-FieldLabel--size{size}"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if value}
|
||||||
|
<div
|
||||||
|
class="spectrum-FieldLabel spectrum-ProgressBar-percentage spectrum-FieldLabel--size{size}"
|
||||||
|
>
|
||||||
|
{Math.round($progress)}%
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="spectrum-ProgressBar-track">
|
||||||
|
<div
|
||||||
|
class="spectrum-ProgressBar-fill"
|
||||||
|
style={value ? `width: ${$progress}%` : ""}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="spectrum-ProgressBar-label" hidden="" />
|
||||||
|
</div>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<script>
|
||||||
|
// WIP! Does not yet work.
|
||||||
|
import "@spectrum-css/progresscircle/dist/index-vars.css"
|
||||||
|
import { tweened } from "svelte/motion"
|
||||||
|
import { cubicOut } from "svelte/easing"
|
||||||
|
|
||||||
|
export let value = false
|
||||||
|
export let small
|
||||||
|
export let large
|
||||||
|
|
||||||
|
export let overBackground
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class:spectrum-ProgressBar--indeterminate={!value}
|
||||||
|
class:spectrum-ProgressCircle--small={small}
|
||||||
|
class:spectrum-ProgressCircle--large={large}
|
||||||
|
class="spectrum-ProgressCircle"
|
||||||
|
>
|
||||||
|
<div class="spectrum-ProgressCircle-track" />
|
||||||
|
<div class="spectrum-ProgressCircle-fills">
|
||||||
|
<div class="spectrum-ProgressCircle-fillMask1">
|
||||||
|
<div class="spectrum-ProgressCircle-fillSubMask1">
|
||||||
|
<div class="spectrum-ProgressCircle-fill" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="spectrum-ProgressCircle-fillMask2">
|
||||||
|
<div class="spectrum-ProgressCircle-fillSubMask2">
|
||||||
|
<div class="spectrum-ProgressCircle-fill" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue