mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-14 18:01:06 +00:00
feat: initial commit
This commit is contained in:
parent
bde7dd644f
commit
72dc38ea56
119 changed files with 14925 additions and 1 deletions
6
.eslintrc.json
Normal file
6
.eslintrc.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parserOptions": { "ecmaVersion": 2019, "sourceType": "module" },
|
||||
"env": { "es6": true, "browser": true },
|
||||
"plugins": ["svelte3"],
|
||||
"overrides": [{ "files": ["**/*.svelte"], "processor": "svelte3/svelte3" }]
|
||||
}
|
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
* @metonym
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/coverage
|
||||
/lib
|
||||
/node_modules
|
||||
.DS_Store
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
*.tgz
|
2
.storybook/addons.js
Normal file
2
.storybook/addons.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
import '@storybook/addon-knobs/register';
|
||||
import '@storybook/addon-storysource/register';
|
6
.storybook/config.js
Normal file
6
.storybook/config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { configure } from '@storybook/svelte';
|
||||
|
||||
// use prebuilt CSS file to refrain from setting up sass, autoprefixer
|
||||
import '!style-loader!css-loader!carbon-components/css/carbon-components.min.css';
|
||||
|
||||
configure(require.context('../src', true, /\.stories\.js$/), module);
|
11
.storybook/webpack.config.js
Normal file
11
.storybook/webpack.config.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = async ({ config }) => {
|
||||
config.module.rules.push({
|
||||
test: [/\.stories\.js$/],
|
||||
loaders: [require.resolve('@storybook/source-loader')],
|
||||
include: [path.resolve(__dirname, '../src')],
|
||||
enforce: 'pre'
|
||||
});
|
||||
return config;
|
||||
};
|
5
.travis.yml
Normal file
5
.travis.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
language: node_js
|
||||
node_js: 10
|
||||
cache: yarn
|
||||
script:
|
||||
- yarn build
|
10
CHANGELOG.md
Normal file
10
CHANGELOG.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.1.0](https://github.com/IBM/carbon-components-svelte/releases/tag/v0.1.0) - 2019-12-15
|
||||
|
||||
- Initial release
|
67
README.md
67
README.md
|
@ -1,2 +1,67 @@
|
|||
# carbon-components-svelte
|
||||
Svelte implementation of the Carbon Design System
|
||||
|
||||
> [🚧🚧🚧 UNDER CONSTRUCTION] Svelte implementation of the Carbon Design System
|
||||
|
||||
This library is a work in progress.
|
||||
|
||||
## Getting Started
|
||||
|
||||
```bash
|
||||
yarn add -D carbon-components carbon-components-svelte carbon-icons-svelte
|
||||
```
|
||||
|
||||
## Supported Components
|
||||
|
||||
Currently, the following components are supported:
|
||||
|
||||
- Accordion
|
||||
- AccordionItem
|
||||
- AccordionSkeleton
|
||||
- Breadcrumb
|
||||
- BreadcrumbItem
|
||||
- BreadcrumbSkeleton
|
||||
- Button
|
||||
- ButtonSkeleton
|
||||
- Checkbox
|
||||
- CheckboxSkeleton
|
||||
- CodeSnippet
|
||||
- CodeSnippetSkeleton
|
||||
- Copy
|
||||
- CopyButton
|
||||
- InlineLoading
|
||||
- Loading
|
||||
- Link
|
||||
- ListItem
|
||||
- OrderedList
|
||||
- SkeletonText
|
||||
- Tag
|
||||
- TagSkeleton
|
||||
- TextArea
|
||||
- TextAreaSkeleton
|
||||
- Toggle
|
||||
- ToggleSkeleton
|
||||
- ToggleSmall
|
||||
- ToggleSmallSkeleton
|
||||
- TooltipDefinition
|
||||
- TooltipIcon
|
||||
- UnorderedList
|
||||
|
||||
## Usage
|
||||
|
||||
```html
|
||||
<script>
|
||||
import { Tag } from 'carbon-components-svelte';
|
||||
</script>
|
||||
|
||||
<Tag>Text</Tag>
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
[Placeholder]
|
||||
|
||||
## [Changelog](CHANGELOG.md)
|
||||
|
||||
## License
|
||||
|
||||
[Apache 2.0](LICENSE)
|
||||
|
|
BIN
docs/favicon.ico
Normal file
BIN
docs/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
73
docs/iframe.html
Normal file
73
docs/iframe.html
Normal file
|
@ -0,0 +1,73 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Storybook</title><meta name="viewport" content="width=device-width,initial-scale=1"><base target="_parent"><style>:not(.sb-show-main) > .sb-main,
|
||||
:not(.sb-show-nopreview) > .sb-nopreview,
|
||||
:not(.sb-show-errordisplay) > .sb-errordisplay {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sb-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 20px;
|
||||
font-family: "Nunito Sans", -apple-system, ".SFNSText-Regular", "San Francisco", BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.sb-heading {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.2px;
|
||||
margin: 10px 0;
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
.sb-nopreview {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sb-nopreview_main {
|
||||
margin: auto;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
background: rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.sb-nopreview_heading {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sb-errordisplay {
|
||||
border: 20px solid rgb(187, 49, 49);
|
||||
background: #222;
|
||||
color: #fff;
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
.sb-errordisplay_code {
|
||||
padding: 10px;
|
||||
background: #000;
|
||||
color: #eee;
|
||||
font-family: "Operator Mono", "Fira Code Retina", "Fira Code", "FiraCode-Retina", "Andale Mono", "Lucida Console", Consolas, Monaco, monospace;
|
||||
}
|
||||
|
||||
.sb-errordisplay pre {
|
||||
white-space: pre-wrap;
|
||||
}</style><script>/* globals window */
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
try {
|
||||
if (window.parent !== window) {
|
||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||
window.__VUE_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__VUE_DEVTOOLS_GLOBAL_HOOK__;
|
||||
}
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('unable to connect to parent frame for connecting dev tools');
|
||||
}</script><style>#root[hidden],
|
||||
#docs-root[hidden] {
|
||||
display: none !important;
|
||||
}</style></head><body><div class="sb-nopreview sb-wrapper"><div class="sb-nopreview_main"><h1 class="sb-nopreview_heading sb-heading">No Preview</h1><p>Sorry, but you either have no stories or none are selected somehow.</p><ul><li>Please check the Storybook config.</li><li>Try reloading the page.</li></ul><p>If the problem persists, check the browser console, or the terminal you've run Storybook from.</p></div></div><div class="sb-errordisplay sb-wrapper"><pre id="error-message" class="sb-heading"></pre><pre class="sb-errordisplay_code"><code id="error-stack"></code></pre></div><div id="root"></div><div id="docs-root"></div><script src="runtime~main.f68146be2ed36b44235a.bundle.js"></script><script src="vendors~main.f68146be2ed36b44235a.bundle.js"></script><script src="main.f68146be2ed36b44235a.bundle.js"></script></body></html>
|
20
docs/index.html
Normal file
20
docs/index.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Storybook</title><meta name="viewport" content="width=device-width,initial-scale=1"><style>html, body {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}</style><script>/* globals window */
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
try {
|
||||
if (window.parent !== window) {
|
||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||
window.__VUE_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__VUE_DEVTOOLS_GLOBAL_HOOK__;
|
||||
}
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('unable to connect to parent frame for connecting dev tools');
|
||||
}</script><style>#root[hidden],
|
||||
#docs-root[hidden] {
|
||||
display: none !important;
|
||||
}</style></head><body><div id="root"></div><div id="docs-root"></div><script>window['DOCS_MODE'] = false;</script><script src="runtime~main.67b3c42af12dc2b7ac9d.bundle.js"></script><script src="vendors~main.de76cb4d691ff902e1d8.bundle.js"></script><script src="main.d19aceecbf99f4b72fa7.bundle.js"></script></body></html>
|
1
docs/main.d19aceecbf99f4b72fa7.bundle.js
Normal file
1
docs/main.d19aceecbf99f4b72fa7.bundle.js
Normal file
|
@ -0,0 +1 @@
|
|||
(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{415:function(n,o,c){c(416),c(529),n.exports=c(878)},438:function(n,o){},529:function(n,o,c){"use strict";c.r(o);c(530),c(850)}},[[415,1,2]]]);
|
2
docs/main.f68146be2ed36b44235a.bundle.js
Normal file
2
docs/main.f68146be2ed36b44235a.bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/main.f68146be2ed36b44235a.bundle.js.map
Normal file
1
docs/main.f68146be2ed36b44235a.bundle.js.map
Normal file
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"main.f68146be2ed36b44235a.bundle.js","sources":["webpack:///main.f68146be2ed36b44235a.bundle.js"],"mappings":"AAAA","sourceRoot":""}
|
1
docs/runtime~main.67b3c42af12dc2b7ac9d.bundle.js
Normal file
1
docs/runtime~main.67b3c42af12dc2b7ac9d.bundle.js
Normal file
|
@ -0,0 +1 @@
|
|||
!function(e){function r(r){for(var n,l,f=r[0],i=r[1],a=r[2],c=0,s=[];c<f.length;c++)l=f[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,a||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,f=1;f<t.length;f++){var i=t[f];0!==o[i]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="";var f=window.webpackJsonp=window.webpackJsonp||[],i=f.push.bind(f);f.push=r,f=f.slice();for(var a=0;a<f.length;a++)r(f[a]);var p=i;t()}([]);
|
2
docs/runtime~main.f68146be2ed36b44235a.bundle.js
Normal file
2
docs/runtime~main.f68146be2ed36b44235a.bundle.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
!function(modules){function webpackJsonpCallback(data){for(var moduleId,chunkId,chunkIds=data[0],moreModules=data[1],executeModules=data[2],i=0,resolves=[];i<chunkIds.length;i++)chunkId=chunkIds[i],Object.prototype.hasOwnProperty.call(installedChunks,chunkId)&&installedChunks[chunkId]&&resolves.push(installedChunks[chunkId][0]),installedChunks[chunkId]=0;for(moduleId in moreModules)Object.prototype.hasOwnProperty.call(moreModules,moduleId)&&(modules[moduleId]=moreModules[moduleId]);for(parentJsonpFunction&&parentJsonpFunction(data);resolves.length;)resolves.shift()();return deferredModules.push.apply(deferredModules,executeModules||[]),checkDeferredModules()}function checkDeferredModules(){for(var result,i=0;i<deferredModules.length;i++){for(var deferredModule=deferredModules[i],fulfilled=!0,j=1;j<deferredModule.length;j++){var depId=deferredModule[j];0!==installedChunks[depId]&&(fulfilled=!1)}fulfilled&&(deferredModules.splice(i--,1),result=__webpack_require__(__webpack_require__.s=deferredModule[0]))}return result}var installedModules={},installedChunks={1:0},deferredModules=[];function __webpack_require__(moduleId){if(installedModules[moduleId])return installedModules[moduleId].exports;var module=installedModules[moduleId]={i:moduleId,l:!1,exports:{}};return modules[moduleId].call(module.exports,module,module.exports,__webpack_require__),module.l=!0,module.exports}__webpack_require__.m=modules,__webpack_require__.c=installedModules,__webpack_require__.d=function(exports,name,getter){__webpack_require__.o(exports,name)||Object.defineProperty(exports,name,{enumerable:!0,get:getter})},__webpack_require__.r=function(exports){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(exports,"__esModule",{value:!0})},__webpack_require__.t=function(value,mode){if(1&mode&&(value=__webpack_require__(value)),8&mode)return value;if(4&mode&&"object"==typeof value&&value&&value.__esModule)return value;var ns=Object.create(null);if(__webpack_require__.r(ns),Object.defineProperty(ns,"default",{enumerable:!0,value:value}),2&mode&&"string"!=typeof value)for(var key in value)__webpack_require__.d(ns,key,function(key){return value[key]}.bind(null,key));return ns},__webpack_require__.n=function(module){var getter=module&&module.__esModule?function getDefault(){return module.default}:function getModuleExports(){return module};return __webpack_require__.d(getter,"a",getter),getter},__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)},__webpack_require__.p="";var jsonpArray=window.webpackJsonp=window.webpackJsonp||[],oldJsonpFunction=jsonpArray.push.bind(jsonpArray);jsonpArray.push=webpackJsonpCallback,jsonpArray=jsonpArray.slice();for(var i=0;i<jsonpArray.length;i++)webpackJsonpCallback(jsonpArray[i]);var parentJsonpFunction=oldJsonpFunction;checkDeferredModules()}([]);
|
||||
//# sourceMappingURL=runtime~main.f68146be2ed36b44235a.bundle.js.map
|
1
docs/runtime~main.f68146be2ed36b44235a.bundle.js.map
Normal file
1
docs/runtime~main.f68146be2ed36b44235a.bundle.js.map
Normal file
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"runtime~main.f68146be2ed36b44235a.bundle.js","sources":["webpack:///runtime~main.f68146be2ed36b44235a.bundle.js"],"mappings":"AAAA","sourceRoot":""}
|
1
docs/sb_dll/storybook_ui-manifest.json
Normal file
1
docs/sb_dll/storybook_ui-manifest.json
Normal file
File diff suppressed because one or more lines are too long
104
docs/sb_dll/storybook_ui_dll.LICENCE
Normal file
104
docs/sb_dll/storybook_ui_dll.LICENCE
Normal file
|
@ -0,0 +1,104 @@
|
|||
/**!
|
||||
* @fileOverview Kickass library to create and place poppers near their reference elements.
|
||||
* @version 1.15.0
|
||||
* @license
|
||||
* Copyright (c) 2016 Federico Zivolo and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* https://github.com/es-shims/es5-shim
|
||||
* @license es5-shim Copyright 2009-2015 by contributors, MIT License
|
||||
* see https://github.com/es-shims/es5-shim/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
/*!
|
||||
* isobject <https://github.com/jonschlinkert/isobject>
|
||||
*
|
||||
* Copyright (c) 2014-2017, Jon Schlinkert.
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* https://github.com/paulmillr/es6-shim
|
||||
* @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com)
|
||||
* and contributors, MIT License
|
||||
* es6-shim: v0.35.4
|
||||
* see https://github.com/paulmillr/es6-shim/blob/0.35.3/LICENSE
|
||||
* Details and documentation:
|
||||
* https://github.com/paulmillr/es6-shim/
|
||||
*/
|
||||
|
||||
/*!
|
||||
Copyright (c) 2017 Jed Watson.
|
||||
Licensed under the MIT License (MIT), see
|
||||
http://jedwatson.github.io/classnames
|
||||
*/
|
||||
|
||||
/** @license React v16.8.6
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v16.8.6
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v0.13.6
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
object-assign
|
||||
(c) Sindre Sorhus
|
||||
@license MIT
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Fuse.js v3.4.5 - Lightweight fuzzy-search (http://fusejs.io)
|
||||
*
|
||||
* Copyright (c) 2012-2017 Kirollos Risk (http://kiro.me)
|
||||
* All Rights Reserved. Apache Software License 2.0
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
|
||||
/** @license React v16.8.6
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
2
docs/sb_dll/storybook_ui_dll.js
Normal file
2
docs/sb_dll/storybook_ui_dll.js
Normal file
File diff suppressed because one or more lines are too long
103
docs/vendors~main.de76cb4d691ff902e1d8.bundle.js
Normal file
103
docs/vendors~main.de76cb4d691ff902e1d8.bundle.js
Normal file
File diff suppressed because one or more lines are too long
81
docs/vendors~main.f68146be2ed36b44235a.bundle.js
Normal file
81
docs/vendors~main.f68146be2ed36b44235a.bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/vendors~main.f68146be2ed36b44235a.bundle.js.map
Normal file
1
docs/vendors~main.f68146be2ed36b44235a.bundle.js.map
Normal file
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"vendors~main.f68146be2ed36b44235a.bundle.js","sources":["webpack:///vendors~main.f68146be2ed36b44235a.bundle.js"],"mappings":"AAAA;;;;;AAk3bA;;;;;AAm0FA;;;;;AAkkEA;;;;;;;;;AAukBA;;;AA8odA;;;;;;;;AAg/BA;;;;;;;;AAqEA;;;;;;;;AAkTA;;;;;;;AAyrDA;;;;;;;AAy7CA;;;;;;;AAogBA;;;;;;;AAfA","sourceRoot":""}
|
120
package.json
Normal file
120
package.json
Normal file
|
@ -0,0 +1,120 @@
|
|||
{
|
||||
"name": "carbon-components-svelte",
|
||||
"version": "0.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Svelte implementation of the Carbon Design System",
|
||||
"svelte": "src/index.js",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.mjs",
|
||||
"scripts": {
|
||||
"start": "start-storybook",
|
||||
"build": "rollup -c",
|
||||
"build:storybook": "build-storybook -o docs",
|
||||
"test": "jest --coverage",
|
||||
"test:tdd": "jest --watch",
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"dependencies": {
|
||||
"carbon-icons-svelte": "^10.8.0-rc.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"carbon-components": "^10.8.0",
|
||||
"carbon-icons-svelte": "^10.8.0-rc.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.7.4",
|
||||
"@babel/preset-env": "^7.7.4",
|
||||
"@commitlint/cli": "^8.2.0",
|
||||
"@commitlint/config-conventional": "^8.2.0",
|
||||
"@storybook/addon-knobs": "^5.2.6",
|
||||
"@storybook/addon-storysource": "^5.2.6",
|
||||
"@storybook/cli": "^5.2.6",
|
||||
"@storybook/svelte": "^5.2.6",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/svelte": "^1.11.0",
|
||||
"babel-jest": "^24.9.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"carbon-components": "10.8.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-svelte3": "^2.7.3",
|
||||
"husky": "^3.1.0",
|
||||
"jest": "^24.9.0",
|
||||
"jest-transform-svelte": "^2.1.0",
|
||||
"lint-staged": "^9.5.0",
|
||||
"prettier": "^1.19.1",
|
||||
"prettier-plugin-svelte": "^0.7.0",
|
||||
"pretty-quick": "^2.0.1",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"rollup": "^1.27.13",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"rollup-plugin-svelte": "^5.1.1",
|
||||
"rollup-plugin-terser": "^5.1.3",
|
||||
"svelte": "^3.16.4",
|
||||
"svelte-loader": "^2.13.6"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Eric Liu",
|
||||
"email": "eric.young.liu@ibm.com"
|
||||
}
|
||||
],
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged && pretty-quick --pattern 'src/**/*.{js,svelte}' --staged",
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,svelte}": [
|
||||
"eslint --fix 'src/**'",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@babel/preset-env"
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
"^.+\\.svelte$": "jest-transform-svelte",
|
||||
"^.+\\.js$": "babel-jest"
|
||||
},
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"svelte"
|
||||
],
|
||||
"setupFilesAfterEnv": [
|
||||
"regenerator-runtime/runtime",
|
||||
"@testing-library/jest-dom/extend-expect"
|
||||
]
|
||||
},
|
||||
"commitlint": {
|
||||
"extends": [
|
||||
"@commitlint/config-conventional"
|
||||
]
|
||||
},
|
||||
"resolutions": {
|
||||
"**/bin-links": ">=1.1.6"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ibm/carbon-components-svelte.git"
|
||||
},
|
||||
"homepage": "https://github.com/ibm/carbon-components-svelte",
|
||||
"keywords": [
|
||||
"carbon",
|
||||
"carbon components",
|
||||
"svelte"
|
||||
],
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"bugs": "https://github.com/ibm/carbon-components-svelte/issues"
|
||||
}
|
24
rollup.config.js
Normal file
24
rollup.config.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { terser } from 'rollup-plugin-terser';
|
||||
import pkg from './package.json';
|
||||
import resolve from 'rollup-plugin-node-resolve';
|
||||
import svelte from 'rollup-plugin-svelte';
|
||||
|
||||
export default ['es', 'umd'].map(format => {
|
||||
const UMD = format === 'umd';
|
||||
|
||||
const output = {
|
||||
format,
|
||||
file: UMD ? pkg.main : pkg.module
|
||||
};
|
||||
|
||||
if (UMD) {
|
||||
output.name = 'carbon-components-svelte';
|
||||
}
|
||||
|
||||
return {
|
||||
input: 'src',
|
||||
output,
|
||||
external: Object.keys(pkg.dependencies || {}),
|
||||
plugins: [svelte(), resolve(), UMD && terser()]
|
||||
};
|
||||
});
|
39
src/components/Accordion/Accordion.Skeleton.svelte
Normal file
39
src/components/Accordion/Accordion.Skeleton.svelte
Normal file
|
@ -0,0 +1,39 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let open = true;
|
||||
export let count = 4;
|
||||
export let props = {};
|
||||
|
||||
import ChevronRight16 from 'carbon-icons-svelte/lib/ChevronRight16';
|
||||
import { cx } from '../../lib';
|
||||
import SkeletonText from '../SkeletonText';
|
||||
|
||||
const _class = cx('--accordion', '--skeleton', className);
|
||||
const skeletonItems = Array.from({ length: open ? count - 1 : count });
|
||||
</script>
|
||||
|
||||
<ul class={_class} {...props}>
|
||||
{#if open}
|
||||
<li class={cx('--accordion__item', '--accordion__item--active')}>
|
||||
<span class={cx('--accordion__heading')}>
|
||||
<ChevronRight16 class={cx('--accordion__arrow')} />
|
||||
<SkeletonText class={cx('--accordion__title')} />
|
||||
</span>
|
||||
<div class={cx('--accordion__content')}>
|
||||
<SkeletonText width="90%" />
|
||||
<SkeletonText width="80%" />
|
||||
<SkeletonText width="95%" />
|
||||
</div>
|
||||
</li>
|
||||
{/if}
|
||||
|
||||
{#each skeletonItems as item}
|
||||
<li class={cx('--accordion__item')}>
|
||||
<span class={cx('--accordion__heading')}>
|
||||
<ChevronRight16 class={cx('--accordion__arrow')} />
|
||||
<SkeletonText class={cx('--accordion__title')} />
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
55
src/components/Accordion/Accordion.Story.svelte
Normal file
55
src/components/Accordion/Accordion.Story.svelte
Normal file
|
@ -0,0 +1,55 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
export let title = undefined;
|
||||
export let open = undefined;
|
||||
export let count = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Accordion from './Accordion.svelte';
|
||||
import AccordionItem from './AccordionItem.svelte';
|
||||
import AccordionSkeleton from './Accordion.Skeleton.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
{#if story === 'skeleton'}
|
||||
<div style="width: 500px">
|
||||
<AccordionSkeleton {open} {count} />
|
||||
</div>
|
||||
{:else}
|
||||
<Accordion>
|
||||
<AccordionItem {title} {open}>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
|
||||
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
||||
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</p>
|
||||
</AccordionItem>
|
||||
<AccordionItem title="Section 2 title">
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
|
||||
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
||||
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</p>
|
||||
</AccordionItem>
|
||||
<AccordionItem title="Section 3 title">
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
|
||||
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
||||
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</p>
|
||||
</AccordionItem>
|
||||
<AccordionItem>
|
||||
<div slot="title">
|
||||
Section 4 title (
|
||||
<em>the title can be a node</em>
|
||||
)
|
||||
</div>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
|
||||
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
||||
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</p>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
{/if}
|
||||
</Layout>
|
21
src/components/Accordion/Accordion.stories.js
Normal file
21
src/components/Accordion/Accordion.stories.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { withKnobs, text, boolean, number } from '@storybook/addon-knobs';
|
||||
import Component from './Accordion.Story.svelte';
|
||||
|
||||
export default { title: 'Accordion', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
title: text('The title (title)', 'Section 1 title'),
|
||||
open: boolean('Open the section (open)', false)
|
||||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'skeleton',
|
||||
open: boolean('Show first item opened (open)', true),
|
||||
count: number('Set number of items (count)', 4)
|
||||
}
|
||||
});
|
11
src/components/Accordion/Accordion.svelte
Normal file
11
src/components/Accordion/Accordion.svelte
Normal file
|
@ -0,0 +1,11 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
</script>
|
||||
|
||||
<ul {...props} class={cx('--accordion', className)}>
|
||||
<slot />
|
||||
</ul>
|
62
src/components/Accordion/AccordionItem.svelte
Normal file
62
src/components/Accordion/AccordionItem.svelte
Normal file
|
@ -0,0 +1,62 @@
|
|||
<script>
|
||||
// NOTE: no 'renderExpando'; use 'expando' named slot
|
||||
// TODO: change 'expando' to something more intuitive?
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let title = undefined;
|
||||
export let iconDescription = 'Expand/Collapse';
|
||||
export let open = false;
|
||||
export let props = {};
|
||||
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import ChevronRight16 from 'carbon-icons-svelte/lib/ChevronRight16';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
let animation = undefined;
|
||||
|
||||
function handleAnimationEnd(event) {
|
||||
animation = undefined;
|
||||
}
|
||||
|
||||
function handleClick(event) {
|
||||
animation = open ? 'collapsing' : 'expanding';
|
||||
open = !open;
|
||||
dispatch('headingclick', { open, event });
|
||||
}
|
||||
|
||||
function handleKeyDown(event) {
|
||||
if (open && event.key === 'Escape') {
|
||||
open = false;
|
||||
}
|
||||
}
|
||||
|
||||
$: _class = cx(
|
||||
'--accordion__item',
|
||||
open && '--accordion__item--active',
|
||||
animation && `--accordion__item--${animation}`,
|
||||
className
|
||||
);
|
||||
$: accordionItemProps = {
|
||||
type: 'button',
|
||||
class: cx('--accordion__heading'),
|
||||
title: iconDescription,
|
||||
'aria-expanded': open,
|
||||
onClick: handleClick,
|
||||
onKeyDown: handleKeyDown
|
||||
};
|
||||
</script>
|
||||
|
||||
<li class={_class} {...props} on:animationend on:animationend={handleAnimationEnd}>
|
||||
<slot name="expando" props={accordionItemProps}>
|
||||
<button {...accordionItemProps} on:click={handleClick} on:keydown={handleKeyDown}>
|
||||
<ChevronRight16 class={cx('--accordion__arrow')} aria-label={iconDescription} />
|
||||
<div class={cx('--accordion__title')}>
|
||||
<slot name="title">{title}</slot>
|
||||
</div>
|
||||
</button>
|
||||
</slot>
|
||||
<div class={cx('--accordion__content')}>
|
||||
<slot />
|
||||
</div>
|
||||
</li>
|
5
src/components/Accordion/index.js
Normal file
5
src/components/Accordion/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import Accordion from './Accordion.svelte';
|
||||
|
||||
export default Accordion;
|
||||
export { default as AccordionItem } from './AccordionItem.svelte';
|
||||
export { default as AccordionSkeleton } from './Accordion.Skeleton.svelte';
|
17
src/components/Breadcrumb/Breadcrumb.Skeleton.svelte
Normal file
17
src/components/Breadcrumb/Breadcrumb.Skeleton.svelte
Normal file
|
@ -0,0 +1,17 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--breadcrumb', '--skeleton', className);
|
||||
</script>
|
||||
|
||||
<div {...props} class={_class}>
|
||||
{#each [0, 1, 2] as item, i (item)}
|
||||
<div class={cx('--breadcrumb-item')}>
|
||||
<span class={cx('--link')}> </span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
39
src/components/Breadcrumb/Breadcrumb.Story.svelte
Normal file
39
src/components/Breadcrumb/Breadcrumb.Story.svelte
Normal file
|
@ -0,0 +1,39 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
export let noTrailingSlash = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Breadcrumb from './Breadcrumb.svelte';
|
||||
import BreadcrumbItem from './BreadcrumbItem.svelte';
|
||||
import BreadcrumbSkeleton from './Breadcrumb.Skeleton.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
{#if story === 'current page'}
|
||||
<Breadcrumb noTrailingSlash>
|
||||
<BreadcrumbItem let:props>
|
||||
<a {...props} href="/#">Breadcrumb 1</a>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbItem href="#">Breadcrumb 2</BreadcrumbItem>
|
||||
<BreadcrumbItem href="#" isCurrentPage>Breadcrumb 3</BreadcrumbItem>
|
||||
</Breadcrumb>
|
||||
{:else if story === 'current page with aria-current'}
|
||||
<Breadcrumb noTrailingSlash>
|
||||
<BreadcrumbItem let:props>
|
||||
<a {...props} href="/#">Breadcrumb 1</a>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbItem href="#">Breadcrumb 2</BreadcrumbItem>
|
||||
<BreadcrumbItem href="#" aria-current="page">Breadcrumb 3</BreadcrumbItem>
|
||||
</Breadcrumb>
|
||||
{:else if story === 'skeleton'}
|
||||
<BreadcrumbSkeleton />
|
||||
{:else}
|
||||
<Breadcrumb {noTrailingSlash}>
|
||||
<BreadcrumbItem let:props>
|
||||
<a {...props} href="/#">Breadcrumb 1</a>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbItem href="#">Breadcrumb 2</BreadcrumbItem>
|
||||
<BreadcrumbItem href="#">Breadcrumb 3</BreadcrumbItem>
|
||||
</Breadcrumb>
|
||||
{/if}
|
||||
</Layout>
|
24
src/components/Breadcrumb/Breadcrumb.stories.js
Normal file
24
src/components/Breadcrumb/Breadcrumb.stories.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { withKnobs, boolean } from '@storybook/addon-knobs';
|
||||
import Component from './Breadcrumb.Story.svelte';
|
||||
|
||||
export default { title: 'Breadcrumb', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: { noTrailingSlash: boolean('No Trailing Slash (noTrailingSlash)', false) }
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({
|
||||
Component,
|
||||
props: { story: 'skeleton' }
|
||||
});
|
||||
|
||||
export const CurrentPage = () => ({
|
||||
Component,
|
||||
props: { story: 'current page' }
|
||||
});
|
||||
|
||||
export const CurrentPageWithAriaCurrent = () => ({
|
||||
Component,
|
||||
props: { story: 'current page with aria-current' }
|
||||
});
|
16
src/components/Breadcrumb/Breadcrumb.svelte
Normal file
16
src/components/Breadcrumb/Breadcrumb.svelte
Normal file
|
@ -0,0 +1,16 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let noTrailingSlash = false;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const ariaLabel = $$props['aria-label'] || 'Breadcrumb';
|
||||
const _class = cx('--breadcrumb', noTrailingSlash && '--breadcrumb--no-trailing-slash');
|
||||
</script>
|
||||
|
||||
<nav class={className} aria-label={ariaLabel}>
|
||||
<ol class={_class}>
|
||||
<slot />
|
||||
</ol>
|
||||
</nav>
|
31
src/components/Breadcrumb/BreadcrumbItem.svelte
Normal file
31
src/components/Breadcrumb/BreadcrumbItem.svelte
Normal file
|
@ -0,0 +1,31 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let href = undefined;
|
||||
export let isCurrentPage = false;
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
import Link from '../Link';
|
||||
|
||||
const ariaCurrent = $$props['aria-current'];
|
||||
|
||||
$: _class = cx(
|
||||
'--breadcrumb-item',
|
||||
isCurrentPage && ariaCurrent !== 'page' && '--breadcrumb-item--current',
|
||||
className
|
||||
);
|
||||
$: itemProps = { 'aria-current': ariaCurrent, class: cx('--link') };
|
||||
</script>
|
||||
|
||||
{#if href}
|
||||
<li class={_class} {...props}>
|
||||
<Link {href} props={itemProps}>
|
||||
<slot />
|
||||
</Link>
|
||||
</li>
|
||||
{:else}
|
||||
<li class={_class} {...props}>
|
||||
<slot props={itemProps} />
|
||||
</li>
|
||||
{/if}
|
5
src/components/Breadcrumb/index.js
Normal file
5
src/components/Breadcrumb/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import Breadcrumb from './Breadcrumb.svelte';
|
||||
|
||||
export default Breadcrumb;
|
||||
export { default as BreadcrumbItem } from './BreadcrumbItem.svelte';
|
||||
export { default as BreadcrumbSkeleton } from './Breadcrumb.Skeleton.svelte';
|
17
src/components/Button/Button.Skeleton.svelte
Normal file
17
src/components/Button/Button.Skeleton.svelte
Normal file
|
@ -0,0 +1,17 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let small = false;
|
||||
export let href = undefined;
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--skeleton', '--btn', small && '--btn--sm', className);
|
||||
</script>
|
||||
|
||||
{#if href}
|
||||
<a {...props} class={_class} {href} role="button">{''}</a>
|
||||
{:else}
|
||||
<div {...props} class={_class} />
|
||||
{/if}
|
73
src/components/Button/Button.Story.svelte
Normal file
73
src/components/Button/Button.Story.svelte
Normal file
|
@ -0,0 +1,73 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Button from './Button.svelte';
|
||||
import ButtonSkeleton from './Button.Skeleton.svelte';
|
||||
import Add16 from 'carbon-icons-svelte/lib/Add16';
|
||||
|
||||
const {
|
||||
kind,
|
||||
disabled,
|
||||
size,
|
||||
renderIcon,
|
||||
iconDescription,
|
||||
small,
|
||||
tooltipPosition,
|
||||
tooltipAlignment
|
||||
} = $$props;
|
||||
|
||||
const regularProps = {
|
||||
kind,
|
||||
disabled,
|
||||
size,
|
||||
iconDescription,
|
||||
small
|
||||
};
|
||||
|
||||
const iconOnlyProps = {
|
||||
kind,
|
||||
disabled,
|
||||
size,
|
||||
renderIcon: Add16,
|
||||
iconDescription,
|
||||
tooltipPosition,
|
||||
tooltipAlignment
|
||||
};
|
||||
|
||||
const setProps = { disabled, small, size, iconDescription };
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
{#if story === 'skeleton'}
|
||||
<ButtonSkeleton />
|
||||
|
||||
<ButtonSkeleton href="#" />
|
||||
|
||||
<ButtonSkeleton small />
|
||||
{:else if story === 'inline'}
|
||||
<Button />
|
||||
{:else if story === 'icon-only buttons'}
|
||||
<Button {...iconOnlyProps} hasIconOnly />
|
||||
{:else if story === 'set of buttons'}
|
||||
<div class={cx('--btn-set')}>
|
||||
<Button kind="secondary" {...setProps}>Secondary button</Button>
|
||||
<Button kind="primary" {...setProps}>Primary button</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<Button {...regularProps}>Button</Button>
|
||||
|
||||
<Button {...regularProps} href="#">Link</Button>
|
||||
|
||||
<Button {...regularProps} as let:props>
|
||||
<p {...props}>Element</p>
|
||||
</Button>
|
||||
|
||||
<Button {...regularProps} as let:props>
|
||||
<a href="#link" {...props}>Custom component</a>
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</Layout>
|
64
src/components/Button/Button.stories.js
Normal file
64
src/components/Button/Button.stories.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { withKnobs, select, boolean, text } from '@storybook/addon-knobs';
|
||||
import Component from './Button.Story.svelte';
|
||||
|
||||
export default { title: 'Button', decorators: [withKnobs] };
|
||||
|
||||
// TODO: add selectable renderIcon for Default, Icon-only stories
|
||||
|
||||
const kinds = {
|
||||
'Primary button (primary)': 'primary',
|
||||
'Secondary button (secondary)': 'secondary',
|
||||
'Danger button (danger)': 'danger',
|
||||
'Ghost button (ghost)': 'ghost'
|
||||
};
|
||||
|
||||
const sizes = {
|
||||
Default: 'default',
|
||||
Field: 'field',
|
||||
Small: 'small'
|
||||
};
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
kind: select('Button kind (kind)', kinds, 'primary'),
|
||||
disabled: boolean('Disabled (disabled)', false),
|
||||
size: select('Button size (size)', sizes, 'default'),
|
||||
iconDescription: text('Icon description (iconDescription)', 'Button icon'),
|
||||
small: boolean('Small (small) - Deprecated in favor of `size`', false)
|
||||
}
|
||||
});
|
||||
|
||||
export const IconOnlyButtons = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'icon-only buttons',
|
||||
kind: select('Button kind (kind)', kinds, 'primary'),
|
||||
disabled: boolean('Disabled (disabled)', false),
|
||||
size: select('Button size (size)', sizes, 'default'),
|
||||
iconDescription: text('Icon description (iconDescription)', 'Button icon'),
|
||||
tooltipPosition: select(
|
||||
'Tooltip position (tooltipPosition)',
|
||||
['top', 'right', 'bottom', 'left'],
|
||||
'bottom'
|
||||
),
|
||||
tooltipAlignment: select(
|
||||
'Tooltip alignment (tooltipAlignment)',
|
||||
['start', 'center', 'end'],
|
||||
'center'
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
export const SetOfButtons = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'set of buttons',
|
||||
disabled: boolean('Disabled (disabled)', false),
|
||||
small: boolean('Small (small)', false),
|
||||
size: select('Button size (size)', sizes, 'default'),
|
||||
iconDescription: text('Icon description (iconDescription)', 'Button icon')
|
||||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({ Component, props: { story: 'skeleton' } });
|
82
src/components/Button/Button.svelte
Normal file
82
src/components/Button/Button.svelte
Normal file
|
@ -0,0 +1,82 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let as = undefined;
|
||||
export let disabled = false;
|
||||
export let size = 'default';
|
||||
export let small = false;
|
||||
export let kind = 'primary';
|
||||
export let href = undefined;
|
||||
export let tabindex = '0';
|
||||
export let type = 'button';
|
||||
export let renderIcon = undefined;
|
||||
export let iconDescription = undefined;
|
||||
export let hasIconOnly = false;
|
||||
export let tooltipPosition = undefined;
|
||||
export let tooltipAlignment = undefined;
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx(
|
||||
'--btn',
|
||||
size === 'field' && '--btn--field',
|
||||
(size === 'small' || small) && '--btn--sm',
|
||||
kind === 'primary' && '--btn--primary',
|
||||
kind === 'danger' && '--btn--danger',
|
||||
kind === 'secondary' && '--btn--secondary',
|
||||
kind === 'ghost' && '--btn--ghost',
|
||||
kind === 'danger--primary' && '--btn--danger--primary',
|
||||
kind === 'tertiary' && '--btn--tertiary',
|
||||
disabled && '--btn--disabled',
|
||||
hasIconOnly && '--btn--icon-only',
|
||||
hasIconOnly && '--tooltip__trigger',
|
||||
hasIconOnly && '--tooltip--a11y',
|
||||
hasIconOnly && tooltipPosition && `--tooltip--${tooltipPosition}`,
|
||||
hasIconOnly && tooltipAlignment && `--tooltip--align-${tooltipAlignment}`,
|
||||
className
|
||||
);
|
||||
const buttonProps = {
|
||||
...props,
|
||||
tabindex,
|
||||
class: _class,
|
||||
disabled,
|
||||
type: href && !disabled ? undefined : type,
|
||||
role: 'button',
|
||||
href
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if as}
|
||||
<slot props={buttonProps} />
|
||||
{:else}
|
||||
{#if href && !disabled}
|
||||
<a {...buttonProps} {href} on:click on:mouseover on:mouseenter on:mouseleave>
|
||||
{#if hasIconOnly}
|
||||
<span class={cx('--assistive-text')}>{iconDescription}</span>
|
||||
{/if}
|
||||
<slot />
|
||||
{#if renderIcon}
|
||||
<svelte:component
|
||||
this={renderIcon}
|
||||
aria-hidden="true"
|
||||
class={cx('--btn__icon')}
|
||||
aria-label={iconDescription} />
|
||||
{/if}
|
||||
</a>
|
||||
{:else}
|
||||
<button {...buttonProps} on:click on:mouseover on:mouseenter on:mouseleave>
|
||||
{#if hasIconOnly}
|
||||
<span class={cx('--assistive-text')}>{iconDescription}</span>
|
||||
{/if}
|
||||
<slot />
|
||||
{#if renderIcon}
|
||||
<svelte:component
|
||||
this={renderIcon}
|
||||
aria-hidden="true"
|
||||
class={cx('--btn__icon')}
|
||||
aria-label={iconDescription} />
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
{/if}
|
4
src/components/Button/index.js
Normal file
4
src/components/Button/index.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import Button from './Button.svelte';
|
||||
|
||||
export default Button;
|
||||
export { default as ButtonSkeleton } from './Button.Skeleton.svelte';
|
13
src/components/Checkbox/Checkbox.Skeleton.svelte
Normal file
13
src/components/Checkbox/Checkbox.Skeleton.svelte
Normal file
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--form-item', '--checkbox-wrapper', className);
|
||||
</script>
|
||||
|
||||
<div {...props} class={_class}>
|
||||
<span class={cx('--checkbox-label', '--skeleton')} />
|
||||
</div>
|
35
src/components/Checkbox/Checkbox.Story.svelte
Normal file
35
src/components/Checkbox/Checkbox.Story.svelte
Normal file
|
@ -0,0 +1,35 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
const { labelText, indeterminate, disabled, hideLabel, wrapperClassName } = $$props;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Checkbox from './Checkbox.svelte';
|
||||
import CheckboxSkeleton from './Checkbox.Skeleton.svelte';
|
||||
|
||||
const checkboxProps = {
|
||||
labelText,
|
||||
indeterminate,
|
||||
disabled,
|
||||
hideLabel,
|
||||
wrapperClassName
|
||||
};
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
{#if story === 'skeleton'}
|
||||
<CheckboxSkeleton />
|
||||
{:else if story === 'unchecked'}
|
||||
<fieldset class={cx('--fieldset')}>
|
||||
<legend class={cx('--label')}>Checkbox heading</legend>
|
||||
<Checkbox {...checkboxProps} id="checkbox-label-1" />
|
||||
<Checkbox {...checkboxProps} id="checkbox-label-2" />
|
||||
</fieldset>
|
||||
{:else}
|
||||
<fieldset class={cx('--fieldset')}>
|
||||
<legend class={cx('--label')}>Checkbox heading</legend>
|
||||
<Checkbox {...checkboxProps} checked id="checkbox-label-1" />
|
||||
<Checkbox {...checkboxProps} checked id="checkbox-label-2" />
|
||||
</fieldset>
|
||||
{/if}
|
||||
</Layout>
|
32
src/components/Checkbox/Checkbox.stories.js
Normal file
32
src/components/Checkbox/Checkbox.stories.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { withKnobs, boolean, text } from '@storybook/addon-knobs';
|
||||
import Component from './Checkbox.Story.svelte';
|
||||
|
||||
export default { title: 'Checkbox', decorators: [withKnobs] };
|
||||
|
||||
export const Checked = () => ({
|
||||
Component,
|
||||
props: {
|
||||
labelText: text('Label text (labelText)', 'Checkbox label'),
|
||||
indeterminate: boolean('Intermediate (indeterminate)', false),
|
||||
disabled: boolean('Disabled (disabled)', false),
|
||||
hideLabel: boolean('No label (hideLabel)', false),
|
||||
wrapperClass: text('Wrapper CSS class name (wrapperClass)', '')
|
||||
}
|
||||
});
|
||||
|
||||
export const Unchecked = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'unchecked',
|
||||
labelText: text('Label text (labelText)', 'Checkbox label'),
|
||||
indeterminate: boolean('Intermediate (indeterminate)', false),
|
||||
disabled: boolean('Disabled (disabled)', false),
|
||||
hideLabel: boolean('No label (hideLabel)', false),
|
||||
wrapperClass: text('Wrapper CSS class name (wrapperClass)', '')
|
||||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({
|
||||
Component,
|
||||
props: { story: 'skeleton' }
|
||||
});
|
41
src/components/Checkbox/Checkbox.svelte
Normal file
41
src/components/Checkbox/Checkbox.svelte
Normal file
|
@ -0,0 +1,41 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let checked = false;
|
||||
export let indeterminate = false;
|
||||
export let disabled = false;
|
||||
export let id = undefined;
|
||||
export let labelText = undefined;
|
||||
export let hideLabel = false;
|
||||
export let title = '';
|
||||
export let wrapperClassName = undefined;
|
||||
export { wrapperClassName as wrapperClass };
|
||||
export let props = {};
|
||||
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const _labelClass = cx('--checkbox-label', className);
|
||||
const _innerLabelClass = cx('--checkbox-label-text', hideLabel && '--visually-hidden');
|
||||
const _wrapperClass = cx('--form-item', '--checkbox-wrapper', wrapperClassName);
|
||||
|
||||
function handleChange(event) {
|
||||
dispatch('change', { checked: event.target.checked, id, event });
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class={_wrapperClass}>
|
||||
<input
|
||||
{...props}
|
||||
type="checkbox"
|
||||
class={cx('--checkbox')}
|
||||
on:change={handleChange}
|
||||
{indeterminate}
|
||||
{disabled}
|
||||
{checked}
|
||||
{id} />
|
||||
<label for={id} class={_labelClass} title={title || null}>
|
||||
<span class={_innerLabelClass}>{labelText}</span>
|
||||
</label>
|
||||
</div>
|
4
src/components/Checkbox/index.js
Normal file
4
src/components/Checkbox/index.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import Checkbox from './Checkbox.svelte';
|
||||
|
||||
export default Checkbox;
|
||||
export { default as CheckboxSkeleton } from './Checkbox.Skeleton.svelte';
|
32
src/components/CodeSnippet/CodeSnippet.Skeleton.svelte
Normal file
32
src/components/CodeSnippet/CodeSnippet.Skeleton.svelte
Normal file
|
@ -0,0 +1,32 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let type = 'single';
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx(
|
||||
'--snippet',
|
||||
'--skeleton',
|
||||
type === 'single' && '--snippet--single',
|
||||
type === 'multi' && '--snippet--multi',
|
||||
className
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if type === 'single'}
|
||||
<div {...props} class={_class}>
|
||||
<div class={cx('--snippet-container')}>
|
||||
<span />
|
||||
</div>
|
||||
</div>
|
||||
{:else if type === 'multi'}
|
||||
<div {...props} class={_class}>
|
||||
<div class={cx('--snippet-container')}>
|
||||
<span />
|
||||
<span />
|
||||
<span />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
57
src/components/CodeSnippet/CodeSnippet.Story.svelte
Normal file
57
src/components/CodeSnippet/CodeSnippet.Story.svelte
Normal file
|
@ -0,0 +1,57 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
const { light, feedback, copyLabel, copyButtonDescription, showLessText, showMoreText } = $$props;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import CodeSnippet from './CodeSnippet.svelte';
|
||||
import CodeSnippetSkeleton from './CodeSnippet.Skeleton.svelte';
|
||||
|
||||
const inlineProps = { light, feedback, copyLabel };
|
||||
const singleLineProps = {
|
||||
feedback,
|
||||
copyButtonDescription,
|
||||
'aria-label': $$props['aria-label']
|
||||
};
|
||||
const multiLineProps = { feedback, showLessText, showMoreText };
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
{#if story === 'skeleton'}
|
||||
<div style="width: 800px">
|
||||
<CodeSnippetSkeleton type="single" props={{ style: 'margin-bottom: 8px' }} />
|
||||
<CodeSnippetSkeleton type="multi" />
|
||||
</div>
|
||||
{:else if story === 'inline'}
|
||||
<CodeSnippet type="inline" {...inlineProps}>{'node -v'}</CodeSnippet>
|
||||
{:else if story === 'single line'}
|
||||
<CodeSnippet type="single" {...singleLineProps}>
|
||||
{'node -v Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, veritatis voluptate id incidunt molestiae officia possimus, quasi itaque alias, architecto hic, dicta fugit? Debitis delectus quidem explicabo vitae fuga laboriosam!'}
|
||||
</CodeSnippet>
|
||||
{:else if story === 'multi line'}
|
||||
<CodeSnippet type="multi" {...multiLineProps}>
|
||||
{`@mixin grid-container {
|
||||
width: 100%;
|
||||
padding-right: padding(mobile);
|
||||
padding-left: padding(mobile);
|
||||
|
||||
@include breakpoint(bp--xs--major) {
|
||||
padding-right: padding(xs);
|
||||
padding-left: padding(xs);
|
||||
}
|
||||
}
|
||||
|
||||
$z-indexes: (
|
||||
modal : 9000,
|
||||
overlay : 8000,
|
||||
dropdown : 7000,
|
||||
header : 6000,
|
||||
footer : 5000,
|
||||
hidden : - 1,
|
||||
overflowHidden: - 1,
|
||||
floating: 10000
|
||||
);`}
|
||||
</CodeSnippet>
|
||||
{/if}
|
||||
</div>
|
||||
</Layout>
|
39
src/components/CodeSnippet/CodeSnippet.stories.js
Normal file
39
src/components/CodeSnippet/CodeSnippet.stories.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { withKnobs, boolean, text } from '@storybook/addon-knobs';
|
||||
import Component from './CodeSnippet.Story.svelte';
|
||||
|
||||
export default { title: 'CodeSnippet', decorators: [withKnobs] };
|
||||
|
||||
export const Inline = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'inline',
|
||||
light: boolean('Light variant (light)', false),
|
||||
feedback: text('Feedback text (feedback)', 'Feedback Enabled 👍'),
|
||||
copyLabel: text('ARIA label for the snippet/copy button (copyLabel)', 'copyable code snippet')
|
||||
}
|
||||
});
|
||||
|
||||
export const SingleLine = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'single line',
|
||||
feedback: text('Feedback text (feedback)', 'Feedback Enabled 👍'),
|
||||
copyButtonDescription: text(
|
||||
'Copy icon description (copyButtonDescription)',
|
||||
'copyable code snippet'
|
||||
),
|
||||
'aria-label': text('ARIA label of the container (ariaLabel)', 'Container label')
|
||||
}
|
||||
});
|
||||
|
||||
export const MultiLine = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'multi line',
|
||||
feedback: text('Feedback text (feedback)', 'Feedback Enabled 👍'),
|
||||
showMoreText: text('Text for "show more" button (showMoreText)', 'Show more'),
|
||||
showLessText: text('Text for "show less" button (showLessText)', 'Show less')
|
||||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({ Component, props: { story: 'skeleton' } });
|
83
src/components/CodeSnippet/CodeSnippet.svelte
Normal file
83
src/components/CodeSnippet/CodeSnippet.svelte
Normal file
|
@ -0,0 +1,83 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let type = 'single';
|
||||
export let feedback = undefined;
|
||||
export let copyButtonDescription = undefined;
|
||||
export let copyLabel = undefined;
|
||||
export let showMoreText = 'Show more';
|
||||
export let showLessText = 'Show less';
|
||||
export let light = false;
|
||||
export let props = {};
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import ChevronDown16 from 'carbon-icons-svelte/lib/ChevronDown16';
|
||||
import { cx } from '../../lib';
|
||||
import Button from '../Button';
|
||||
import Copy from '../Copy';
|
||||
import CopyButton from '../CopyButton';
|
||||
|
||||
const id = Math.random();
|
||||
let codeRef = undefined;
|
||||
let expandedCode = false;
|
||||
let shouldShowMoreLessBtn = false;
|
||||
|
||||
onMount(() => {
|
||||
if (codeRef) {
|
||||
const { height } = codeRef.getBoundingClientRect();
|
||||
shouldShowMoreLessBtn = type === 'multi' && height > 255;
|
||||
}
|
||||
});
|
||||
|
||||
$: _class = cx(
|
||||
'--snippet',
|
||||
type && `--snippet--${type}`,
|
||||
expandedCode && '--snippet--expand',
|
||||
light && '--snippet--light',
|
||||
className
|
||||
);
|
||||
$: expandCodeBtnText = expandedCode ? showLessText : showMoreText;
|
||||
</script>
|
||||
|
||||
{#if type === 'inline'}
|
||||
<Copy
|
||||
on:click
|
||||
aria-label={copyLabel || $$props['aria-label']}
|
||||
aria-describedby={id}
|
||||
class={_class}
|
||||
{feedback}
|
||||
{props}>
|
||||
<code {id}>
|
||||
<slot />
|
||||
</code>
|
||||
</Copy>
|
||||
{:else}
|
||||
<div {...props} class={_class}>
|
||||
<div
|
||||
role="textbox"
|
||||
tabindex="0"
|
||||
class={cx('--snippet-container')}
|
||||
aria-label={$$props['aria-label'] || copyLabel || 'code-snippet'}>
|
||||
<code>
|
||||
<pre bind:this={codeRef}>
|
||||
<slot />
|
||||
</pre>
|
||||
</code>
|
||||
</div>
|
||||
<CopyButton on:click {feedback} iconDescription={copyButtonDescription} />
|
||||
{#if shouldShowMoreLessBtn}
|
||||
<Button
|
||||
kind="ghost"
|
||||
size="small"
|
||||
class={cx('--snippet-btn--expand')}
|
||||
on:click={() => {
|
||||
expandedCode = !expandedCode;
|
||||
}}>
|
||||
<span class={cx('--snippet-btn--text')}>{expandCodeBtnText}</span>
|
||||
<ChevronDown16
|
||||
aria-label={expandCodeBtnText}
|
||||
class={cx('--icon-chevron--down', '--snippet__icon')} />
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
4
src/components/CodeSnippet/index.js
Normal file
4
src/components/CodeSnippet/index.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import CodeSnippet from './CodeSnippet.svelte';
|
||||
|
||||
export default CodeSnippet;
|
||||
export { default as CodeSnippetSkeleton } from './CodeSnippet.Skeleton.svelte';
|
45
src/components/Copy/Copy.svelte
Normal file
45
src/components/Copy/Copy.svelte
Normal file
|
@ -0,0 +1,45 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let feedback = 'Copied!';
|
||||
export let feedbackTimeout = 2000;
|
||||
export let props = {};
|
||||
|
||||
import { createEventDispatcher, onDestroy } from 'svelte';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let timeoutId = undefined;
|
||||
let showFeedback = false;
|
||||
|
||||
function handleClick(event) {
|
||||
showFeedback = true;
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
showFeedback = false;
|
||||
}, feedbackTimeout);
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (timeoutId !== undefined) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
$: _class = cx('--btn--copy__feedback', showFeedback && '--btn--copy__feedback--displayed');
|
||||
</script>
|
||||
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class={className}
|
||||
on:click
|
||||
on:click={handleClick}
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave>
|
||||
<slot />
|
||||
<div class={_class} data-feedback={feedback} />
|
||||
</button>
|
3
src/components/Copy/index.js
Normal file
3
src/components/Copy/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Copy from './Copy.svelte';
|
||||
|
||||
export default Copy;
|
10
src/components/CopyButton/CopyButton.Story.svelte
Normal file
10
src/components/CopyButton/CopyButton.Story.svelte
Normal file
|
@ -0,0 +1,10 @@
|
|||
<script>
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import CopyButton from './CopyButton.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<div style="position: relative;">
|
||||
<CopyButton {...$$props} />
|
||||
</div>
|
||||
</Layout>
|
13
src/components/CopyButton/CopyButton.stories.js
Normal file
13
src/components/CopyButton/CopyButton.stories.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { withKnobs, text, number } from '@storybook/addon-knobs';
|
||||
import Component from './CopyButton.Story.svelte';
|
||||
|
||||
export default { title: 'CopyButton', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
feedback: text('The text shown upon clicking (feedback)', 'Copied!'),
|
||||
feedbackTimeout: number('How long the text is shown upon clicking (feedbackTimeout)', 3000),
|
||||
iconDescription: text('Feedback icon description (iconDescription)', 'Copy to clipboard')
|
||||
}
|
||||
});
|
62
src/components/CopyButton/CopyButton.svelte
Normal file
62
src/components/CopyButton/CopyButton.svelte
Normal file
|
@ -0,0 +1,62 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let iconDescription = 'Copy to clipboard';
|
||||
export let feedback = 'Copied!';
|
||||
export let feedbackTimeout = 2000;
|
||||
export let props = {};
|
||||
|
||||
import { createEventDispatcher, onDestroy } from 'svelte';
|
||||
import Copy16 from 'carbon-icons-svelte/lib/Copy16';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
let animation = undefined;
|
||||
let timeoutId = undefined;
|
||||
|
||||
onDestroy(() => {
|
||||
if (timeoutId !== undefined) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
function handleClick(event) {
|
||||
animation = 'fade-in';
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
animation = 'fade-out';
|
||||
}, feedbackTimeout);
|
||||
}
|
||||
|
||||
function handleAnimationEnd(event) {
|
||||
if (event.animationName === 'hide-feedback') {
|
||||
animation = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
$: _class = cx(
|
||||
'--snippet-button', // TODO: deprecated?
|
||||
'--copy-btn',
|
||||
animation && '--copy-btn--animating',
|
||||
animation && `--copy-btn--${animation}`,
|
||||
className
|
||||
);
|
||||
</script>
|
||||
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
aria-label={iconDescription}
|
||||
title={iconDescription}
|
||||
class={_class}
|
||||
on:click
|
||||
on:click={handleClick}
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
on:animationend
|
||||
on:animationend={handleAnimationEnd}>
|
||||
<span class={cx('--assistive-text', '--copy-btn__feedback')}>{feedback}</span>
|
||||
<Copy16 class={cx('--snippet__icon')} />
|
||||
</button>
|
3
src/components/CopyButton/index.js
Normal file
3
src/components/CopyButton/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import CopyButton from './CopyButton.svelte';
|
||||
|
||||
export default CopyButton;
|
67
src/components/InlineLoading/InlineLoading.Story.svelte
Normal file
67
src/components/InlineLoading/InlineLoading.Story.svelte
Normal file
|
@ -0,0 +1,67 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
export let status = undefined;
|
||||
export let iconDescription = undefined;
|
||||
export let description = undefined;
|
||||
export let successDelay = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Button from '../Button';
|
||||
import InlineLoading from './InlineLoading.svelte';
|
||||
|
||||
const props = { status, iconDescription, description, successDelay };
|
||||
|
||||
let isSubmitting = false;
|
||||
let success = false;
|
||||
let ariaLive = 'off';
|
||||
let loadingDescription = 'Submitting...';
|
||||
|
||||
function handleSubmit() {
|
||||
isSubmitting = true;
|
||||
ariaLive = 'assertive';
|
||||
|
||||
setTimeout(() => {
|
||||
isSubmitting = false;
|
||||
loadingDescription = 'Submitted!';
|
||||
success = true;
|
||||
setTimeout(() => {
|
||||
success = false;
|
||||
isSubmitting = false;
|
||||
loadingDescription = 'Submitting...';
|
||||
ariaLive = 'off';
|
||||
}, 1500);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
$: disabled = isSubmitting || success;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.wrapper {
|
||||
display: flex;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
:global(.loader) {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<Layout>
|
||||
{#if story === 'ux-example'}
|
||||
<div class="wrapper">
|
||||
<Button kind="secondary" {disabled}>Cancel</Button>
|
||||
{#if disabled}
|
||||
<InlineLoading
|
||||
class="loader"
|
||||
description={loadingDescription}
|
||||
status={success ? 'finished' : 'active'}
|
||||
aria-live={ariaLive} />
|
||||
{:else}
|
||||
<Button on:click={handleSubmit}>Submit</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<InlineLoading {...props} />
|
||||
{/if}
|
||||
</Layout>
|
30
src/components/InlineLoading/InlineLoading.stories.js
Normal file
30
src/components/InlineLoading/InlineLoading.stories.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { withKnobs, select, text, number } from '@storybook/addon-knobs';
|
||||
import Component from './InlineLoading.Story.svelte';
|
||||
|
||||
export default { title: 'InlineLoading', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
status: select(
|
||||
'Loading status (status)',
|
||||
['inactive', 'active', 'finished', 'error'],
|
||||
'active'
|
||||
),
|
||||
iconDescription: text('Icon description (iconDescription)', 'Active loading indicator'),
|
||||
description: text('Loading progress description (description)', 'Loading data...'),
|
||||
successDelay: number(
|
||||
'The duration for successful state before `onSuccess` fires (successDelay)',
|
||||
1500
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
export const UxExample = () => ({
|
||||
Component,
|
||||
props: { story: 'ux-example' }
|
||||
});
|
||||
|
||||
UxExample.story = {
|
||||
name: 'UX Example'
|
||||
};
|
52
src/components/InlineLoading/InlineLoading.svelte
Normal file
52
src/components/InlineLoading/InlineLoading.svelte
Normal file
|
@ -0,0 +1,52 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let success = false; // TODO: deprecate
|
||||
export let status = success ? 'finished' : 'active';
|
||||
export let description = undefined;
|
||||
export let iconDescription = undefined;
|
||||
export let successDelay = 1500;
|
||||
export let props = {};
|
||||
|
||||
import { createEventDispatcher, onDestroy } from 'svelte';
|
||||
import CheckmarkFilled16 from 'carbon-icons-svelte/lib/CheckmarkFilled16';
|
||||
import Error20 from 'carbon-icons-svelte/lib/Error20';
|
||||
import { cx } from '../../lib';
|
||||
import Loading from '../Loading';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const _class = cx('--inline-loading', className);
|
||||
let timeoutId = undefined;
|
||||
|
||||
onDestroy(() => {
|
||||
if (timeoutId !== undefined) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
$: if (status === 'finished') {
|
||||
timeoutId = setTimeout(() => {
|
||||
dispatch('success');
|
||||
}, successDelay);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div {...props} class={_class} aria-live={$$props['aria-live'] || 'assertive'}>
|
||||
<div class={cx('--inline-loading__animation')}>
|
||||
{#if status === 'error'}
|
||||
<Error20 class={cx('--inline-loading--error')} />
|
||||
{:else if status === 'finished'}
|
||||
<CheckmarkFilled16 class={cx('--inline-loading__checkmark-container')} />
|
||||
{:else if status === 'inactive' || status === 'active'}
|
||||
<Loading
|
||||
small
|
||||
description={iconDescription}
|
||||
withOverlay={false}
|
||||
active={status === 'active'} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if description}
|
||||
<div class={cx('--inline-loading__text')}>{description}</div>
|
||||
{/if}
|
||||
</div>
|
3
src/components/InlineLoading/index.js
Normal file
3
src/components/InlineLoading/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import InlineLoading from './InlineLoading.svelte';
|
||||
|
||||
export default InlineLoading;
|
14
src/components/Link/Link.Story.svelte
Normal file
14
src/components/Link/Link.Story.svelte
Normal file
|
@ -0,0 +1,14 @@
|
|||
<script>
|
||||
export let href = undefined;
|
||||
export let inline = undefined;
|
||||
export let disabled = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Link from './Link.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
<Link {href} {inline} {disabled}>Link</Link>
|
||||
</div>
|
||||
</Layout>
|
13
src/components/Link/Link.stories.js
Normal file
13
src/components/Link/Link.stories.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { withKnobs, boolean, text } from '@storybook/addon-knobs';
|
||||
import Component from './Link.Story.svelte';
|
||||
|
||||
export default { title: 'Link', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
href: text('The link href (href)', '#'),
|
||||
inline: boolean('Use the in-line variant (inline)', false),
|
||||
disabled: boolean('Disabled (disabled)', false)
|
||||
}
|
||||
});
|
27
src/components/Link/Link.svelte
Normal file
27
src/components/Link/Link.svelte
Normal file
|
@ -0,0 +1,27 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let href = undefined;
|
||||
export let disabled = false;
|
||||
export let inline = false;
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx(
|
||||
'--link',
|
||||
disabled && '--link--disabled',
|
||||
inline && '--link--inline',
|
||||
className
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if disabled}
|
||||
<p {...props} class={_class}>
|
||||
<slot />
|
||||
</p>
|
||||
{:else}
|
||||
<a {...props} class={_class} {href}>
|
||||
<slot />
|
||||
</a>
|
||||
{/if}
|
3
src/components/Link/index.js
Normal file
3
src/components/Link/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Link from './Link.svelte';
|
||||
|
||||
export default Link;
|
13
src/components/ListItem/ListItem.svelte
Normal file
13
src/components/ListItem/ListItem.svelte
Normal file
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--list__item', className);
|
||||
</script>
|
||||
|
||||
<li {...props} class={_class}>
|
||||
<slot />
|
||||
</li>
|
3
src/components/ListItem/index.js
Normal file
3
src/components/ListItem/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import ListItem from './ListItem.svelte';
|
||||
|
||||
export default ListItem;
|
8
src/components/Loading/Loading.Story.svelte
Normal file
8
src/components/Loading/Loading.Story.svelte
Normal file
|
@ -0,0 +1,8 @@
|
|||
<script>
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Loading from './Loading.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<Loading {...$$props} />
|
||||
</Layout>
|
14
src/components/Loading/Loading.stories.js
Normal file
14
src/components/Loading/Loading.stories.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { withKnobs, boolean, text } from '@storybook/addon-knobs';
|
||||
import Component from './Loading.Story.svelte';
|
||||
|
||||
export default { title: 'Loading', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
active: boolean('Active (active)', true),
|
||||
withOverlay: boolean('With overlay (withOverlay)', false),
|
||||
small: boolean('Small (small)', false),
|
||||
description: text('Description (description)', 'Active loading indicator')
|
||||
}
|
||||
});
|
57
src/components/Loading/Loading.svelte
Normal file
57
src/components/Loading/Loading.svelte
Normal file
|
@ -0,0 +1,57 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let active = true;
|
||||
export let withOverlay = true;
|
||||
export let small = false;
|
||||
export let description = 'Active loading indicator';
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const loadingId = `loading-id-${Math.random()}`;
|
||||
const spinnerRadius = small ? '26.8125' : '37.5';
|
||||
const _class = cx(
|
||||
'--loading',
|
||||
small && '--loading--small',
|
||||
!active && '--loading--stop',
|
||||
className
|
||||
);
|
||||
const _overlayClass = cx('--loading-overlay', !active && '--loading-overlay--stop');
|
||||
</script>
|
||||
|
||||
{#if withOverlay}
|
||||
<div class={_overlayClass}>
|
||||
<div
|
||||
{...props}
|
||||
aria-atomic="true"
|
||||
aria-labelledby={loadingId}
|
||||
aria-live={active ? 'assertive' : 'off'}
|
||||
class={_class}>
|
||||
<label id={loadingId} class={cx('--visually-hidden')}>{description}</label>
|
||||
<svg class={cx('--loading__svg')} viewBox="-75 -75 150 150">
|
||||
<title>{description}</title>
|
||||
{#if small}
|
||||
<circle class={cx('--loading__background')} cx="0" cy="0" r={spinnerRadius} />
|
||||
{/if}
|
||||
<circle class={cx('--loading__stroke')} cx="0" cy="0" r={spinnerRadius} />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
{...props}
|
||||
aria-atomic="true"
|
||||
aria-labelledby={loadingId}
|
||||
aria-live={active ? 'assertive' : 'off'}
|
||||
class={_class}>
|
||||
<label id={loadingId} class={cx('--visually-hidden')}>{description}</label>
|
||||
<svg class={cx('--loading__svg')} viewBox="-75 -75 150 150">
|
||||
<title>{description}</title>
|
||||
{#if small}
|
||||
<circle class={cx('--loading__background')} cx="0" cy="0" r={spinnerRadius} />
|
||||
{/if}
|
||||
<circle class={cx('--loading__stroke')} cx="0" cy="0" r={spinnerRadius} />
|
||||
</svg>
|
||||
</div>
|
||||
{/if}
|
3
src/components/Loading/index.js
Normal file
3
src/components/Loading/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Loading from './Loading.svelte';
|
||||
|
||||
export default Loading;
|
37
src/components/OrderedList/OrderedList.Story.svelte
Normal file
37
src/components/OrderedList/OrderedList.Story.svelte
Normal file
|
@ -0,0 +1,37 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import ListItem from '../ListItem';
|
||||
import OrderedList from './OrderedList.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
{#if story === 'nested'}
|
||||
<OrderedList>
|
||||
<ListItem>
|
||||
Unordered List level 1
|
||||
<OrderedList nested>
|
||||
<ListItem>Ordered List level 2</ListItem>
|
||||
<ListItem>
|
||||
Ordered List level 2
|
||||
<OrderedList nested>
|
||||
<ListItem>Ordered List level 2</ListItem>
|
||||
<ListItem>Ordered List level 2</ListItem>
|
||||
</OrderedList>
|
||||
</ListItem>
|
||||
</OrderedList>
|
||||
</ListItem>
|
||||
<ListItem>Ordered List level 1</ListItem>
|
||||
<ListItem>Ordered List level 1</ListItem>
|
||||
</OrderedList>
|
||||
{:else}
|
||||
<OrderedList>
|
||||
<ListItem>Ordered List level 1</ListItem>
|
||||
<ListItem>Ordered List level 1</ListItem>
|
||||
<ListItem>Ordered List level 1</ListItem>
|
||||
</OrderedList>
|
||||
{/if}
|
||||
</div>
|
||||
</Layout>
|
8
src/components/OrderedList/OrderedList.stories.js
Normal file
8
src/components/OrderedList/OrderedList.stories.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { withKnobs } from '@storybook/addon-knobs';
|
||||
import Component from './OrderedList.Story.svelte';
|
||||
|
||||
export default { title: 'Ordered List', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({ Component });
|
||||
|
||||
export const Nested = () => ({ Component, props: { story: 'nested' } });
|
14
src/components/OrderedList/OrderedList.svelte
Normal file
14
src/components/OrderedList/OrderedList.svelte
Normal file
|
@ -0,0 +1,14 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let nested = false;
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--list--ordered', nested && '--list--nested', className);
|
||||
</script>
|
||||
|
||||
<ol {...props} class={_class}>
|
||||
<slot />
|
||||
</ol>
|
3
src/components/OrderedList/index.js
Normal file
3
src/components/OrderedList/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import OrderedList from './OrderedList.svelte';
|
||||
|
||||
export default OrderedList;
|
10
src/components/SkeletonText/SkeletonText.Story.svelte
Normal file
10
src/components/SkeletonText/SkeletonText.Story.svelte
Normal file
|
@ -0,0 +1,10 @@
|
|||
<script>
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import SkeletonText from './SkeletonText.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<div style="width: 300px">
|
||||
<SkeletonText {...$$props} />
|
||||
</div>
|
||||
</Layout>
|
18
src/components/SkeletonText/SkeletonText.stories.js
Normal file
18
src/components/SkeletonText/SkeletonText.stories.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { withKnobs, select, boolean, number } from '@storybook/addon-knobs';
|
||||
import Component from './SkeletonText.Story.svelte';
|
||||
|
||||
export default { title: 'SkeletonText', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
heading: boolean('Skeleton text at a larger size (heading)'),
|
||||
paragraph: boolean('Use multiple lines of text (paragraph)'),
|
||||
lineCount: number('The number of lines in a paragraph (lineCount)', 3),
|
||||
width: select(
|
||||
'Width (in px or %) of single line of text or max-width of paragraph lines (width)',
|
||||
{ '100%': '100%', '250px': '250px' },
|
||||
'100%'
|
||||
)
|
||||
}
|
||||
});
|
37
src/components/SkeletonText/SkeletonText.svelte
Normal file
37
src/components/SkeletonText/SkeletonText.svelte
Normal file
|
@ -0,0 +1,37 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let paragraph = false;
|
||||
export let lineCount = 3;
|
||||
export let width = '100%';
|
||||
export let heading = false;
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const randoms = [0.973051493507435, 0.15334737213558558, 0.5671034553053769];
|
||||
const _class = cx('--skeleton__text', heading && '--skeleton__heading', className);
|
||||
const widthNum = parseInt(width, 10);
|
||||
const widthPx = width.includes('px');
|
||||
const widthPercent = width.includes('%');
|
||||
let lines = [];
|
||||
|
||||
$: if (paragraph) {
|
||||
for (let i = 0; i < lineCount; i++) {
|
||||
const min = widthPx ? widthNum - 75 : 0;
|
||||
const max = widthPx ? widthNum : 75;
|
||||
const randomWidth = Math.floor(randoms[i % 3] * (max - min + 1)) + min + 'px';
|
||||
lines = [...lines, { width: widthPx ? randomWidth : `calc(${width} - ${randomWidth})` }];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if paragraph}
|
||||
<div>
|
||||
{#each lines as { width }}
|
||||
<p {...props} class={_class} style={`width: ${width};`} />
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<p {...props} class={_class} style={`width: ${width};`} />
|
||||
{/if}
|
3
src/components/SkeletonText/index.js
Normal file
3
src/components/SkeletonText/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import SkeletonText from './SkeletonText.svelte';
|
||||
|
||||
export default SkeletonText;
|
5
src/components/Tag/Tag.Skeleton.svelte
Normal file
5
src/components/Tag/Tag.Skeleton.svelte
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
import { cx } from '../../lib';
|
||||
</script>
|
||||
|
||||
<span class={cx('--tag', '--skeleton')} />
|
23
src/components/Tag/Tag.Story.svelte
Normal file
23
src/components/Tag/Tag.Story.svelte
Normal file
|
@ -0,0 +1,23 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
export let type = undefined;
|
||||
export let disabled = undefined;
|
||||
export let filter = undefined;
|
||||
export let slot = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Tag from './Tag.svelte';
|
||||
import TagSkeleton from './Tag.Skeleton.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
{#if story === 'filter'}
|
||||
<Tag {filter}>{slot}</Tag>
|
||||
{:else if story === 'skeleton'}
|
||||
<TagSkeleton />
|
||||
{:else}
|
||||
<Tag {disabled} {type}>{slot}</Tag>
|
||||
{/if}
|
||||
</div>
|
||||
</Layout>
|
29
src/components/Tag/Tag.stories.js
Normal file
29
src/components/Tag/Tag.stories.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { withKnobs, select, boolean, text } from '@storybook/addon-knobs';
|
||||
import Component from './Tag.Story.svelte';
|
||||
import { TYPES } from './constants';
|
||||
|
||||
export default { title: 'Tag', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
type: select(
|
||||
'Tag type (type)',
|
||||
Object.keys(TYPES).reduce((items, item) => ({ ...items, [`${item} (${item})`]: item }), {}),
|
||||
'red'
|
||||
),
|
||||
disabled: boolean('Disabled (disabled)', false),
|
||||
slot: text('Content ($$slot)', 'This is not a tag')
|
||||
}
|
||||
});
|
||||
|
||||
export const Filter = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'filter',
|
||||
filter: true,
|
||||
slot: text('Content ($$slot)', 'This is not a tag')
|
||||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({ Component, props: { story: 'skeleton' } });
|
40
src/components/Tag/Tag.svelte
Normal file
40
src/components/Tag/Tag.svelte
Normal file
|
@ -0,0 +1,40 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let type = undefined;
|
||||
export let disabled = false;
|
||||
export let filter = false;
|
||||
export let title = 'Clear filter';
|
||||
export let props = {};
|
||||
|
||||
import Close16 from 'carbon-icons-svelte/lib/Close16';
|
||||
import { cx } from '../../lib';
|
||||
import { TYPES } from './constants';
|
||||
|
||||
const _class = cx(
|
||||
'--tag',
|
||||
type && `--tag--${type}`,
|
||||
disabled && '--tag--disabled',
|
||||
filter && '--tag--filter',
|
||||
className
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if filter}
|
||||
<span
|
||||
{...props}
|
||||
tabindex="0"
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
class={_class}
|
||||
{title}>
|
||||
<slot>{TYPES[type]}</slot>
|
||||
<Close16 aria-label={title} />
|
||||
</span>
|
||||
{:else}
|
||||
<span {...props} on:click on:mouseover on:mouseenter on:mouseleave class={_class}>
|
||||
<slot>{TYPES[type]}</slot>
|
||||
</span>
|
||||
{/if}
|
12
src/components/Tag/constants.js
Normal file
12
src/components/Tag/constants.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
export const TYPES = {
|
||||
red: 'Red',
|
||||
magenta: 'Magenta',
|
||||
purple: 'Purple',
|
||||
blue: 'Blue',
|
||||
cyan: 'Cyan',
|
||||
teal: 'Teal',
|
||||
green: 'Green',
|
||||
gray: 'Gray',
|
||||
'cool-gray': 'Cool-Gray',
|
||||
'warm-gray': 'Warm-Gray'
|
||||
};
|
4
src/components/Tag/index.js
Normal file
4
src/components/Tag/index.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import Tag from './Tag.svelte';
|
||||
|
||||
export default Tag;
|
||||
export { default as TagSkeleton } from './Tag.Skeleton.svelte';
|
17
src/components/TextArea/TextArea.Skeleton.svelte
Normal file
17
src/components/TextArea/TextArea.Skeleton.svelte
Normal file
|
@ -0,0 +1,17 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let hideLabel = false;
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--form-item', className);
|
||||
</script>
|
||||
|
||||
<div {...props} class={_class}>
|
||||
{#if !hideLabel}
|
||||
<span class={cx('--label', '--skeleton')} />
|
||||
{/if}
|
||||
<div class={cx('--skeleton', '--text-area')} />
|
||||
</div>
|
17
src/components/TextArea/TextArea.Story.svelte
Normal file
17
src/components/TextArea/TextArea.Story.svelte
Normal file
|
@ -0,0 +1,17 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import TextArea from './TextArea.svelte';
|
||||
import TextAreaSkeleton from './TextArea.Skeleton.svelte';
|
||||
|
||||
let value = '';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
{#if story === 'skeleton'}
|
||||
<TextAreaSkeleton {...$$props} />
|
||||
{:else}
|
||||
<TextArea {...$$props} bind:value />
|
||||
{/if}
|
||||
</Layout>
|
23
src/components/TextArea/TextArea.stories.js
Normal file
23
src/components/TextArea/TextArea.stories.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { withKnobs, boolean, text, number } from '@storybook/addon-knobs';
|
||||
import Component from './TextArea.Story.svelte';
|
||||
|
||||
export default { title: 'TextArea', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
id: 'text-area',
|
||||
disabled: boolean('Disabled (disabled)', false),
|
||||
light: boolean('Light variant (light)', false),
|
||||
hideLabel: boolean('No label (hideLabel)', false),
|
||||
labelText: text('Label text (labelText)', 'Text Area label'),
|
||||
invalid: boolean('Show form validation UI (invalid)', false),
|
||||
invalidText: text('Content of form validation UI (invalidText)', 'A valid value is required'),
|
||||
helperText: text('Helper text (helperText)', 'Optional helper text.'),
|
||||
placeholder: text('Placeholder text (placeholder)', 'Placeholder text.'),
|
||||
cols: number('Columns (columns)', 50),
|
||||
rows: number('Rows (rows)', 4)
|
||||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({ Component, props: { story: 'skeleton' } });
|
89
src/components/TextArea/TextArea.svelte
Normal file
89
src/components/TextArea/TextArea.svelte
Normal file
|
@ -0,0 +1,89 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let cols = 50;
|
||||
export let disabled = false;
|
||||
export let id = Math.random();
|
||||
export let labelText = undefined;
|
||||
export let placeholder = '';
|
||||
export let rows = 4;
|
||||
export let value = undefined;
|
||||
export let invalid = false;
|
||||
export let invalidText = undefined;
|
||||
export let helperText = undefined;
|
||||
export let hideLabel = false;
|
||||
export let light = false;
|
||||
export let props = {};
|
||||
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import WarningFilled16 from 'carbon-icons-svelte/lib/WarningFilled16';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const errorId = `${id}-error`;
|
||||
const _labelClass = cx(
|
||||
'--label',
|
||||
hideLabel && '--visually-hidden',
|
||||
disabled && '--label--disabled'
|
||||
);
|
||||
const _helperTextClass = cx('--form__helper-text', disabled && '--form__helper-text--disabled');
|
||||
const _textAreaClass = cx(
|
||||
'--text-area',
|
||||
light && '--text-area--light',
|
||||
invalid && '--text-area--invalid',
|
||||
className
|
||||
);
|
||||
|
||||
function handleClick(event) {
|
||||
if (!disabled) {
|
||||
dispatch('click', event);
|
||||
}
|
||||
}
|
||||
|
||||
function handleChange(event) {
|
||||
if (!disabled) {
|
||||
dispatch('change', event);
|
||||
}
|
||||
}
|
||||
|
||||
function handleInput(event) {
|
||||
if (!disabled) {
|
||||
dispatch('input', event);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class={cx('--form-item')}>
|
||||
{#if labelText && !hideLabel}
|
||||
<label for={id} class={_labelClass}>{labelText}</label>
|
||||
{/if}
|
||||
{#if helperText}
|
||||
<div class={_helperTextClass}>{helperText}</div>
|
||||
{/if}
|
||||
<div class={cx('--text-area__wrapper')} data-invalid={invalid || undefined}>
|
||||
{#if invalid}
|
||||
<WarningFilled16 class={cx('--text-area__invalid-icon')} />
|
||||
{/if}
|
||||
<textarea
|
||||
{...props}
|
||||
on:click
|
||||
on:click={handleClick}
|
||||
on:change
|
||||
on:change={handleChange}
|
||||
on:input
|
||||
on:input={handleInput}
|
||||
class={_textAreaClass}
|
||||
aria-invalid={invalid || undefined}
|
||||
aria-describedby={invalid ? errorId : undefined}
|
||||
{disabled}
|
||||
{id}
|
||||
{cols}
|
||||
{rows}
|
||||
{value}
|
||||
{placeholder}
|
||||
{value} />
|
||||
</div>
|
||||
{#if invalid}
|
||||
<div class={cx('--form-requirement')} id={errorId}>{invalidText}</div>
|
||||
{/if}
|
||||
</div>
|
4
src/components/TextArea/index.js
Normal file
4
src/components/TextArea/index.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import TextArea from './TextArea.svelte';
|
||||
|
||||
export default TextArea;
|
||||
export { default as TextAreaSkeleton } from './TextArea.Skeleton.svelte';
|
24
src/components/Toggle/Toggle.Skeleton.svelte
Normal file
24
src/components/Toggle/Toggle.Skeleton.svelte
Normal file
|
@ -0,0 +1,24 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let id = undefined;
|
||||
export let labelText = undefined;
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--form-item', className);
|
||||
const ariaLabel = labelText ? null : $$props['aria-label'] || 'Toggle is loading';
|
||||
</script>
|
||||
|
||||
<div {...props} class={_class}>
|
||||
<input type="checkbox" class={cx('--toggle --skeleton')} {id} />
|
||||
<label class={cx('--toggle__label', '--skeleton')} aria-label={ariaLabel} for={id}>
|
||||
{#if labelText}
|
||||
<span class={cx('--toggle__label-text')}>{labelText}</span>
|
||||
{/if}
|
||||
<span class={cx('--toggle__text--left')} />
|
||||
<span class={cx('--toggle__appearance')} />
|
||||
<span class={cx('--toggle__text--right')} />
|
||||
</label>
|
||||
</div>
|
17
src/components/Toggle/Toggle.Story.svelte
Normal file
17
src/components/Toggle/Toggle.Story.svelte
Normal file
|
@ -0,0 +1,17 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Toggle from './Toggle.svelte';
|
||||
import ToggleSkeleton from './Toggle.Skeleton.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
{#if story === 'toggled'}
|
||||
<Toggle {...$$props} id="toggle-1" toggled />
|
||||
{:else if story === 'skeleton'}
|
||||
<ToggleSkeleton />
|
||||
{:else}
|
||||
<Toggle {...$$props} id="toggle-1" />
|
||||
{/if}
|
||||
</Layout>
|
31
src/components/Toggle/Toggle.stories.js
Normal file
31
src/components/Toggle/Toggle.stories.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { withKnobs, boolean, text } from '@storybook/addon-knobs';
|
||||
import Component from './Toggle.Story.svelte';
|
||||
|
||||
export default { title: 'Toggle', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
labelText: text('Label toggle input control (labelText)', ''),
|
||||
'aria-label': text('ARIA label of the toggle (aria-label)', ''),
|
||||
labelA: text('Label for untoggled state (labelA)', 'Off'),
|
||||
labelB: text('Label for toggled state (labelB)', 'On'),
|
||||
disabled: boolean('Disabled (disabled)', false)
|
||||
}
|
||||
});
|
||||
|
||||
Default.story = { name: 'Default (untoggled)' };
|
||||
|
||||
export const Toggled = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'toggled',
|
||||
labelText: text('Label toggle input control (labelText)', ''),
|
||||
'aria-label': text('ARIA label of the toggle (aria-label)', ''),
|
||||
labelA: text('Label for untoggled state (labelA)', 'Off'),
|
||||
labelB: text('Label for toggled state (labelB)', 'On'),
|
||||
disabled: boolean('Disabled (disabled)', false)
|
||||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({ Component, props: { story: 'skeleton' } });
|
56
src/components/Toggle/Toggle.svelte
Normal file
56
src/components/Toggle/Toggle.svelte
Normal file
|
@ -0,0 +1,56 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let id = Math.random();
|
||||
export let toggled = false;
|
||||
export let disabled = false;
|
||||
export let labelText = undefined;
|
||||
export let labelA = 'Off';
|
||||
export let labelB = 'On';
|
||||
export let props = {};
|
||||
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const _class = cx('--form-item', className);
|
||||
const ariaLabel = labelText ? undefined : $$props['aria-label'] || 'Toggle';
|
||||
let inputRef = undefined;
|
||||
|
||||
function handleChange(event) {
|
||||
dispatch('change', event);
|
||||
dispatch('toggle', { checked: inputRef.checked, id, event });
|
||||
}
|
||||
|
||||
function handleKeyUp(event) {
|
||||
if (event.key === 'Enter') {
|
||||
if (inputRef) {
|
||||
inputRef.checked = !inputRef.checked;
|
||||
}
|
||||
|
||||
handleChange(event);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class={_class}>
|
||||
<input
|
||||
{...props}
|
||||
type="checkbox"
|
||||
class={cx('--toggle-input')}
|
||||
bind:this={inputRef}
|
||||
checked={toggled}
|
||||
{disabled}
|
||||
{id}
|
||||
on:change
|
||||
on:change={handleChange}
|
||||
on:keyup
|
||||
on:keyup={handleKeyUp} />
|
||||
<label class={cx('--toggle-input__label')} for={id} aria-label={ariaLabel}>
|
||||
{labelText}
|
||||
<span class={cx('--toggle__switch')}>
|
||||
<span aria-hidden="true" class={cx('--toggle__text--off')}>{labelA}</span>
|
||||
<span aria-hidden="true" class={cx('--toggle__text--on')}>{labelB}</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
4
src/components/Toggle/index.js
Normal file
4
src/components/Toggle/index.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import Toggle from './Toggle.svelte';
|
||||
|
||||
export default Toggle;
|
||||
export { default as ToggleSkeleton } from './Toggle.Skeleton.svelte';
|
26
src/components/ToggleSmall/ToggleSmall.Skeleton.svelte
Normal file
26
src/components/ToggleSmall/ToggleSmall.Skeleton.svelte
Normal file
|
@ -0,0 +1,26 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let id = undefined;
|
||||
export let labelText = undefined;
|
||||
export let props = {};
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--form-item', className);
|
||||
const ariaLabel = labelText ? undefined : $$props['aria-label'] || 'Toggle is loading';
|
||||
</script>
|
||||
|
||||
<div {...props} class={_class}>
|
||||
<input type="checkbox" class={cx('--toggle', '--toggle--small', '--skeleton')} {id} />
|
||||
<label class={cx('--toggle__label --skeleton')} for={id}>
|
||||
{#if labelText}
|
||||
<span class={cx('--toggle__label-text')}>{labelText}</span>
|
||||
{/if}
|
||||
<span class={cx('--toggle__appearance')}>
|
||||
<svg class={cx('--toggle__check')} width="6" height="5" viewBox="0 0 6 5">
|
||||
<path d="M2.2403 2.7299L4.9245 0 6 1.1117 2.2384 5 0 2.6863 1.0612 1.511z" />
|
||||
</svg>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
17
src/components/ToggleSmall/ToggleSmall.Story.svelte
Normal file
17
src/components/ToggleSmall/ToggleSmall.Story.svelte
Normal file
|
@ -0,0 +1,17 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import ToggleSmall from './ToggleSmall.svelte';
|
||||
import ToggleSmallSkeleton from './ToggleSmall.Skeleton.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
{#if story === 'toggled'}
|
||||
<ToggleSmall {...$$props} id="toggle-1" toggled />
|
||||
{:else if story === 'skeleton'}
|
||||
<ToggleSmallSkeleton />
|
||||
{:else}
|
||||
<ToggleSmall {...$$props} id="toggle-1" />
|
||||
{/if}
|
||||
</Layout>
|
31
src/components/ToggleSmall/ToggleSmall.stories.js
Normal file
31
src/components/ToggleSmall/ToggleSmall.stories.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { withKnobs, boolean, text } from '@storybook/addon-knobs';
|
||||
import Component from './ToggleSmall.Story.svelte';
|
||||
|
||||
export default { title: 'ToggleSmall', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
labelText: text('Label toggle input control (labelText)', ''),
|
||||
'aria-label': text('ARIA label of the toggle (aria-label)', ''),
|
||||
labelA: text('Label for untoggled state (labelA)', 'Off'),
|
||||
labelB: text('Label for toggled state (labelB)', 'On'),
|
||||
disabled: boolean('Disabled (disabled)', false)
|
||||
}
|
||||
});
|
||||
|
||||
Default.story = { name: 'Default (untoggled)' };
|
||||
|
||||
export const Toggled = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'toggled',
|
||||
labelText: text('Label toggle input control (labelText)', ''),
|
||||
'aria-label': text('ARIA label of the toggle (aria-label)', ''),
|
||||
labelA: text('Label for untoggled state (labelA)', 'Off'),
|
||||
labelB: text('Label for toggled state (labelB)', 'On'),
|
||||
disabled: boolean('Disabled (disabled)', false)
|
||||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({ Component, props: { story: 'skeleton' } });
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue