Merge pull request #205 from IBM/refactor
Refactor components to use $$restProps API, add `ref` prop to interactive components
|
@ -1,2 +1,2 @@
|
|||
import '@storybook/addon-knobs/register';
|
||||
import '@storybook/addon-storysource/register';
|
||||
import "@storybook/addon-knobs/register";
|
||||
import "@storybook/addon-storysource/register";
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { configure } from '@storybook/svelte';
|
||||
import { configure } from "@storybook/svelte";
|
||||
|
||||
configure(require.context('../src', true, /\.stories\.js$/), module);
|
||||
configure(require.context("../src", true, /\.stories\.js$/), module);
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
<style>
|
||||
.layout {
|
||||
padding: 3em;
|
||||
body {
|
||||
padding: 3rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="layout">
|
||||
<slot />
|
||||
</div>
|
|
@ -1 +1,4 @@
|
|||
<link rel="stylesheet" href="https://unpkg.com/carbon-components/css/carbon-components.min.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/carbon-components/css/carbon-components.min.css"
|
||||
/>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
const path = require('path');
|
||||
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'
|
||||
loaders: [require.resolve("@storybook/source-loader")],
|
||||
include: [path.resolve(__dirname, "../src")],
|
||||
enforce: "pre",
|
||||
});
|
||||
return config;
|
||||
};
|
||||
|
|
|
@ -2,5 +2,6 @@ language: node_js
|
|||
node_js: 10
|
||||
cache: yarn
|
||||
script:
|
||||
- yarn test
|
||||
- yarn prepack
|
||||
- yarn build
|
||||
- cd docs && yarn && yarn test
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
# Contributing
|
||||
|
||||
## Getting Started
|
||||
## Prerequisites
|
||||
|
||||
### Prerequisites
|
||||
This project uses Node.js and Yarn.
|
||||
|
||||
This project uses node (>=10) and yarn (>=1).
|
||||
- [Node.js](https://nodejs.org/en/download/package-manager/#macos) (version >=10)
|
||||
- [Yarn](https://yarnpkg.com/en/docs/install#mac-stable)
|
||||
|
||||
- [node](https://nodejs.org/en/download/package-manager/#macos) (version 10.x or greater)
|
||||
- [yarn](https://yarnpkg.com/en/docs/install#mac-stable) (version 1.x or greater)
|
||||
|
||||
### Fork and Clone
|
||||
## Fork and Clone
|
||||
|
||||
Fork the repo and clone your fork:
|
||||
|
||||
|
@ -26,7 +24,7 @@ git remote add upstream git@github.com:IBM/carbon-components-svelte.git
|
|||
git remote -v
|
||||
```
|
||||
|
||||
### Install
|
||||
## Install
|
||||
|
||||
Install the project dependencies:
|
||||
|
||||
|
@ -38,19 +36,7 @@ yarn install
|
|||
|
||||
## Workflow
|
||||
|
||||
### Repo Structure
|
||||
|
||||
```js
|
||||
.storybook // Storybook configuration
|
||||
docs // static, exported Storybook used by GitHub Pages
|
||||
src
|
||||
│
|
||||
└───components // individual components
|
||||
└───internal // code excluded from the component library
|
||||
└───lib // shared utilities
|
||||
```
|
||||
|
||||
### Developing
|
||||
### Develop
|
||||
|
||||
This project uses Storybook for UI development and "live" documentation.
|
||||
|
||||
|
@ -62,12 +48,10 @@ yarn start
|
|||
|
||||
#### Component Format
|
||||
|
||||
Individual components are located in the `src/components` folder:
|
||||
|
||||
Each component should adopt the following structure:
|
||||
|
||||
```js
|
||||
src/components/Component
|
||||
src/Component
|
||||
│
|
||||
└───Component.svelte // main component
|
||||
└───Component.Skeleton.svelte // Skeleton component (if any)
|
||||
|
@ -76,7 +60,7 @@ src/components/Component
|
|||
└───index.js // export components (e.g. `Component.svelte`, `Component.Skeleton.svelte`)
|
||||
```
|
||||
|
||||
### Building
|
||||
### Build
|
||||
|
||||
#### Component Library
|
||||
|
||||
|
@ -89,11 +73,11 @@ The library should be compiled in two formats:
|
|||
|
||||
#### Storybook
|
||||
|
||||
To build the Storybook, run `yarn build:storybook`.
|
||||
To build the Storybook, run `yarn build`.
|
||||
|
||||
The Storybook should be outputted to the `docs` folder.
|
||||
The Storybook should be outputted to the `storybook-static` folder.
|
||||
|
||||
## Submitting a Pull Request
|
||||
## Submit a Pull Request
|
||||
|
||||
### Sync Your Fork
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
> Svelte implementation of the [Carbon Design System](https://github.com/carbon-design-system)
|
||||
|
||||
## [Storybook](https://ibm.github.io/carbon-components-svelte) · [CodeSandbox](https://codesandbox.io/s/carbon-components-svelte021-lhvc4)
|
||||
## [Storybook](https://ibm.github.io/carbon-components-svelte)
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
@ -25,7 +25,7 @@ yarn add -D carbon-components-svelte
|
|||
<svelte:head>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/carbon-components@10.9.0/css/carbon-components.min.css"
|
||||
href="https://unpkg.com/carbon-components/css/carbon-components.min.css"
|
||||
/>
|
||||
</svelte:head>
|
||||
|
||||
|
|
3
docs/.cfignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
!Staticfile
|
||||
!public
|
8
docs/.gitignore
vendored
|
@ -1,5 +1,7 @@
|
|||
.DS_Store
|
||||
/__sapper__
|
||||
/**/node_modules
|
||||
/public
|
||||
/public/
|
||||
/node_modules/
|
||||
/src/node_modules/@sapper/
|
||||
yarn-error.log
|
||||
/cypress/screenshots/
|
||||
/__sapper__/
|
||||
|
|
26
docs/README.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
# docs
|
||||
|
||||
This application was scaffolded using the default webpack [Sapper](https://github.com/sveltejs/sapper) template.
|
||||
|
||||
## Deploying to IBM Cloud
|
||||
|
||||
Deploy to IBM Cloud using the Staticfile buildpack.
|
||||
|
||||
### Log in
|
||||
|
||||
Log in using the IBM Cloud CLI:
|
||||
|
||||
```sh
|
||||
ibmcloud login
|
||||
|
||||
# if using Single-Sign On (SSO):
|
||||
ibmcloud login --sso
|
||||
```
|
||||
|
||||
### Deploy
|
||||
|
||||
```sh
|
||||
yarn build
|
||||
ibmcloud target --cf
|
||||
ibmcloud cf push
|
||||
```
|
3
docs/Staticfile
Normal file
|
@ -0,0 +1,3 @@
|
|||
root: public
|
||||
location_include: includes/*.conf
|
||||
force_https: true
|
5
docs/cypress.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"baseUrl": "http://localhost:3000",
|
||||
"video": false,
|
||||
"defaultCommandTimeout": 1000
|
||||
}
|
11
docs/cypress/integration/Button.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
describe("Button", () => {
|
||||
beforeEach(() => {
|
||||
cy.examples("Button");
|
||||
});
|
||||
|
||||
it("renders correctly", () => {
|
||||
cy.get("button").then(($) => {
|
||||
expect($.length).to.eql(4);
|
||||
});
|
||||
});
|
||||
});
|
21
docs/cypress/plugins/index.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
/// <reference types="cypress" />
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
}
|
3
docs/cypress/support/commands.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
Cypress.Commands.add("examples", (component) => {
|
||||
cy.visit(`/examples/${component}`);
|
||||
});
|
1
docs/cypress/support/index.js
Normal file
|
@ -0,0 +1 @@
|
|||
import "./commands";
|
5
docs/includes/header.conf
Normal file
|
@ -0,0 +1,5 @@
|
|||
location ~* ((service-worker)\.js)$ {
|
||||
add_header 'Cache-Control' 'no-store';
|
||||
expires off;
|
||||
proxy_no_cache 1;
|
||||
}
|
7
docs/manifest.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
applications:
|
||||
- name: carbon-svelte
|
||||
memory: 32M
|
||||
disk_quota: 32M
|
||||
buildpacks:
|
||||
- https://github.com/cloudfoundry/staticfile-buildpack.git
|
|
@ -1,30 +1,25 @@
|
|||
{
|
||||
"name": "sapper-webpack",
|
||||
"description": "Custom Sapper webpack template",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"develop": "sapper dev",
|
||||
"build": "sapper export"
|
||||
"dev": "sapper dev",
|
||||
"build": "shx rm -rf public && sapper export && shx mv __sapper__/export public",
|
||||
"cy:run": "cypress run",
|
||||
"cy:open": "cypress open",
|
||||
"test": "run-p --race dev cy:run",
|
||||
"test:tdd": "run-p --race dev cy:open"
|
||||
},
|
||||
"dependencies": {
|
||||
"polka": "next",
|
||||
"sirv": "^0.4.0"
|
||||
"sirv": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@metonym/sapper": "^0.27.12",
|
||||
"autoprefixer": "^9.7.6",
|
||||
"carbon-components": "^10.11.2",
|
||||
"css-loader": "^3.5.3",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
"style-loader": "^1.2.1",
|
||||
"svelte": "~3.20.0",
|
||||
"carbon-components-svelte": "../",
|
||||
"cypress": "^4.10.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"sapper": "^0.27.16",
|
||||
"shx": "^0.3.2",
|
||||
"svelte": "^3.24.0",
|
||||
"svelte-loader": "^2.9.0",
|
||||
"webpack": "^4.43.0",
|
||||
"carbon-components-svelte": "../"
|
||||
"webpack": "^4.7.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import "./style.scss";
|
||||
import * as sapper from "@sapper/app";
|
||||
|
||||
sapper.start({ target: document.querySelector("#sapper") });
|
||||
|
|
33
docs/src/components/GlobalHeader.svelte
Normal file
|
@ -0,0 +1,33 @@
|
|||
<script>
|
||||
export let segment = undefined;
|
||||
|
||||
import {
|
||||
SkipToContent,
|
||||
Header,
|
||||
HeaderNav,
|
||||
HeaderNavItem,
|
||||
HeaderUtilities,
|
||||
HeaderActionLink
|
||||
} from "carbon-components-svelte";
|
||||
</script>
|
||||
|
||||
<Header
|
||||
company="Carbon"
|
||||
platformName="Components Svelte"
|
||||
href="."
|
||||
rel="prefetch"
|
||||
aria-current={segment === undefined ? 'page' : undefined}>
|
||||
<SkipToContent />
|
||||
<HeaderNav>
|
||||
<HeaderNavItem
|
||||
rel="prefetch"
|
||||
href="about"
|
||||
text="About"
|
||||
aria-current={segment === 'about' ? 'page' : undefined} />
|
||||
<HeaderNavItem
|
||||
rel="prefetch"
|
||||
href="components"
|
||||
text="Components"
|
||||
aria-current={segment === 'components' ? 'page' : undefined} />
|
||||
</HeaderNav>
|
||||
</Header>
|
|
@ -1,20 +0,0 @@
|
|||
<script>
|
||||
export let segment;
|
||||
|
||||
import {
|
||||
Button,
|
||||
Header,
|
||||
HeaderNav,
|
||||
HeaderNavItem
|
||||
} from "carbon-components-svelte";
|
||||
|
||||
$: {
|
||||
console.log(segment);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Header company="" platformName="Carbon Components Svelte" href="/">
|
||||
<HeaderNav>
|
||||
<HeaderNavItem href="/about" text="Link 1" />
|
||||
</HeaderNav>
|
||||
</Header>
|
|
@ -1,8 +1,8 @@
|
|||
<script>
|
||||
export let status;
|
||||
export let error;
|
||||
export let error = {};
|
||||
|
||||
const dev = process.env.NODE_ENV === "development";
|
||||
import { Link } from "carbon-components-svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -11,8 +11,11 @@
|
|||
|
||||
<h1>{status}</h1>
|
||||
|
||||
<p>{error.message}</p>
|
||||
<div>
|
||||
{error.message}.
|
||||
<Link href=".">Return home</Link>
|
||||
</div>
|
||||
|
||||
{#if dev && error.stack}
|
||||
{#if process.env.NODE_ENV === 'development' && error.stack}
|
||||
<pre>{error.stack}</pre>
|
||||
{/if}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
<script>
|
||||
import Nav from "../components/Nav.svelte";
|
||||
export let segment = undefined;
|
||||
|
||||
export let segment;
|
||||
import { Content } from "carbon-components-svelte";
|
||||
import GlobalHeader from "../components/GlobalHeader.svelte";
|
||||
</script>
|
||||
|
||||
<style>
|
||||
main {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<Nav {segment} />
|
||||
|
||||
<main>
|
||||
{#if segment !== 'examples'}
|
||||
<GlobalHeader {segment} />
|
||||
<Content>
|
||||
<slot />
|
||||
</Content>
|
||||
{:else}
|
||||
<slot />
|
||||
</main>
|
||||
{/if}
|
||||
|
|
|
@ -1,18 +1,6 @@
|
|||
<script>
|
||||
import {
|
||||
Button,
|
||||
Header,
|
||||
HeaderNav,
|
||||
HeaderNavItem
|
||||
} from "carbon-components-svelte";
|
||||
import { theme } from "../store";
|
||||
</script>
|
||||
<h1>About</h1>
|
||||
|
||||
<svelte:head>
|
||||
<title>About</title>
|
||||
</svelte:head>
|
||||
<h1>About this site</h1>
|
||||
{$theme}
|
||||
<Button>Hello world</Button>
|
||||
|
||||
<p>This is the 'about' page. There's not much here.</p>
|
||||
<p>
|
||||
<code>carbon-components-svelte</code>
|
||||
is the Svelte implementation of the Carbon Design System
|
||||
</p>
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import posts from "./_posts.js";
|
||||
|
||||
const lookup = new Map();
|
||||
|
||||
posts.forEach((post) => {
|
||||
lookup.set(post.slug, JSON.stringify(post));
|
||||
});
|
||||
|
||||
export function get(req, res, next) {
|
||||
// the `slug` parameter is available because
|
||||
// this file is called [slug].json.js
|
||||
const { slug } = req.params;
|
||||
|
||||
if (lookup.has(slug)) {
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
res.end(lookup.get(slug));
|
||||
} else {
|
||||
res.writeHead(404, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify({ message: `Not found` }));
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
<script context="module">
|
||||
export async function preload({ params, query }) {
|
||||
// the `slug` parameter is available because
|
||||
// this file is called [slug].svelte
|
||||
const res = await this.fetch(`blog/${params.slug}.json`);
|
||||
const data = await res.json();
|
||||
|
||||
if (res.status === 200) {
|
||||
return { post: data };
|
||||
} else {
|
||||
this.error(res.status, data.message);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export let post;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{post.title}</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>{post.title}</h1>
|
||||
|
||||
<div class="content">
|
||||
{@html post.html}
|
||||
</div>
|
|
@ -1,92 +0,0 @@
|
|||
// Ordinarily, you'd generate this data from markdown files in your
|
||||
// repo, or fetch them from a database of some kind. But in order to
|
||||
// avoid unnecessary dependencies in the starter template, and in the
|
||||
// service of obviousness, we're just going to leave it here.
|
||||
|
||||
// This file is called `_posts.js` rather than `posts.js`, because
|
||||
// we don't want to create an `/blog/posts` route — the leading
|
||||
// underscore tells Sapper not to do that.
|
||||
|
||||
const posts = [
|
||||
{
|
||||
title: "What is Sapper?",
|
||||
slug: "what-is-sapper",
|
||||
html: `
|
||||
<p>First, you have to know what <a href='https://svelte.dev'>Svelte</a> is. Svelte is a UI framework with a bold new idea: rather than providing a library that you write code with (like React or Vue, for example), it's a compiler that turns your components into highly optimized vanilla JavaScript. If you haven't already read the <a href='https://svelte.dev/blog/frameworks-without-the-framework'>introductory blog post</a>, you should!</p>
|
||||
|
||||
<p>Sapper is a Next.js-style framework (<a href='blog/how-is-sapper-different-from-next'>more on that here</a>) built around Svelte. It makes it embarrassingly easy to create extremely high performance web apps. Out of the box, you get:</p>
|
||||
|
||||
<ul>
|
||||
<li>Code-splitting, dynamic imports and hot module replacement, powered by webpack</li>
|
||||
<li>Server-side rendering (SSR) with client-side hydration</li>
|
||||
<li>Service worker for offline support, and all the PWA bells and whistles</li>
|
||||
<li>The nicest development experience you've ever had, or your money back</li>
|
||||
</ul>
|
||||
|
||||
<p>It's implemented as Express middleware. Everything is set up and waiting for you to get started, but you keep complete control over the server, service worker, webpack config and everything else, so it's as flexible as you need it to be.</p>
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
title: "How to use Sapper",
|
||||
slug: "how-to-use-sapper",
|
||||
html: `
|
||||
<h2>Step one</h2>
|
||||
<p>Create a new project, using <a href='https://github.com/Rich-Harris/degit'>degit</a>:</p>
|
||||
|
||||
<pre><code>npx degit "sveltejs/sapper-template#rollup" my-app
|
||||
cd my-app
|
||||
npm install # or yarn!
|
||||
npm run dev
|
||||
</code></pre>
|
||||
|
||||
<h2>Step two</h2>
|
||||
<p>Go to <a href='http://localhost:3000'>localhost:3000</a>. Open <code>my-app</code> in your editor. Edit the files in the <code>src/routes</code> directory or add new ones.</p>
|
||||
|
||||
<h2>Step three</h2>
|
||||
<p>...</p>
|
||||
|
||||
<h2>Step four</h2>
|
||||
<p>Resist overdone joke formats.</p>
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
title: "Why the name?",
|
||||
slug: "why-the-name",
|
||||
html: `
|
||||
<p>In war, the soldiers who build bridges, repair roads, clear minefields and conduct demolitions — all under combat conditions — are known as <em>sappers</em>.</p>
|
||||
|
||||
<p>For web developers, the stakes are generally lower than those for combat engineers. But we face our own hostile environment: underpowered devices, poor network connections, and the complexity inherent in front-end engineering. Sapper, which is short for <strong>S</strong>velte <strong>app</strong> mak<strong>er</strong>, is your courageous and dutiful ally.</p>
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
title: "How is Sapper different from Next.js?",
|
||||
slug: "how-is-sapper-different-from-next",
|
||||
html: `
|
||||
<p><a href='https://github.com/zeit/next.js'>Next.js</a> is a React framework from <a href='https://zeit.co'>Zeit</a>, and is the inspiration for Sapper. There are a few notable differences, however:</p>
|
||||
|
||||
<ul>
|
||||
<li>It's powered by <a href='https://svelte.dev'>Svelte</a> instead of React, so it's faster and your apps are smaller</li>
|
||||
<li>Instead of route masking, we encode route parameters in filenames. For example, the page you're looking at right now is <code>src/routes/blog/[slug].svelte</code></li>
|
||||
<li>As well as pages (Svelte components, which render on server or client), you can create <em>server routes</em> in your <code>routes</code> directory. These are just <code>.js</code> files that export functions corresponding to HTTP methods, and receive Express <code>request</code> and <code>response</code> objects as arguments. This makes it very easy to, for example, add a JSON API such as the one <a href='blog/how-is-sapper-different-from-next.json'>powering this very page</a></li>
|
||||
<li>Links are just <code><a></code> elements, rather than framework-specific <code><Link></code> components. That means, for example, that <a href='blog/how-can-i-get-involved'>this link right here</a>, despite being inside a blob of HTML, works with the router as you'd expect.</li>
|
||||
</ul>
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
title: "How can I get involved?",
|
||||
slug: "how-can-i-get-involved",
|
||||
html: `
|
||||
<p>We're so glad you asked! Come on over to the <a href='https://github.com/sveltejs/svelte'>Svelte</a> and <a href='https://github.com/sveltejs/sapper'>Sapper</a> repos, and join us in the <a href='https://svelte.dev/chat'>Discord chatroom</a>. Everyone is welcome, especially you!</p>
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
posts.forEach((post) => {
|
||||
post.html = post.html.replace(/^\t{3}/gm, "");
|
||||
});
|
||||
|
||||
export default posts;
|
|
@ -1,34 +0,0 @@
|
|||
<script context="module">
|
||||
export function preload({ params, query }) {
|
||||
return this.fetch(`blog.json`)
|
||||
.then(r => r.json())
|
||||
.then(posts => {
|
||||
return { posts };
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export let posts;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
ul {
|
||||
margin: 0 0 1em 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
<svelte:head>
|
||||
<title>Blog</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>Recent posts</h1>
|
||||
|
||||
<ul>
|
||||
{#each posts as post}
|
||||
<li>
|
||||
<a rel="prefetch" href="blog/{post.slug}">{post.title}</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
17
docs/src/routes/components/[slug].json.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import components from "./_components.js";
|
||||
|
||||
const componentsMap = new Map();
|
||||
|
||||
components.forEach((post) => {
|
||||
componentsMap.set(post.slug, JSON.stringify(post));
|
||||
});
|
||||
|
||||
export function get(req, res, next) {
|
||||
if (componentsMap.has(req.params.slug)) {
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
res.end(componentsMap.get(req.params.slug));
|
||||
} else {
|
||||
res.writeHead(404, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify({ message: "Not found" }));
|
||||
}
|
||||
}
|
38
docs/src/routes/components/[slug].svelte
Normal file
|
@ -0,0 +1,38 @@
|
|||
<script context="module">
|
||||
export async function preload({ params }) {
|
||||
const res = await this.fetch(`components/${params.slug}.json`);
|
||||
const data = await res.json();
|
||||
|
||||
if (res.status === 200) {
|
||||
return { data };
|
||||
} else {
|
||||
this.error(res.status, data.message);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export let data = {};
|
||||
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let component = undefined;
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
component = await import(`../examples/${data.title}.svelte`);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{data.title}</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>{data.title}</h1>
|
||||
|
||||
{#if component}
|
||||
<svelte:component this={component.default} />
|
||||
{/if}
|
10
docs/src/routes/components/_components.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
const components = [
|
||||
{
|
||||
title: "Button",
|
||||
},
|
||||
].map((post) => ({
|
||||
...post,
|
||||
slug: post.title.toLowerCase().replace(/\s+/g, "-"),
|
||||
}));
|
||||
|
||||
export default components;
|
|
@ -1,6 +1,6 @@
|
|||
import posts from "./_posts.js";
|
||||
import components from "./_components.js";
|
||||
|
||||
export function get(req, res) {
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify(posts));
|
||||
res.end(JSON.stringify(components));
|
||||
}
|
27
docs/src/routes/components/index.svelte
Normal file
|
@ -0,0 +1,27 @@
|
|||
<script context="module">
|
||||
export function preload() {
|
||||
return this.fetch("components.json")
|
||||
.then(r => r.json())
|
||||
.then(data => ({ data }));
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export let data = [];
|
||||
|
||||
import { UnorderedList, ListItem, Link } from "carbon-components-svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Components</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>Components</h1>
|
||||
|
||||
<UnorderedList>
|
||||
{#each data as data, i (data.title)}
|
||||
<ListItem>
|
||||
<Link rel="prefetch" href="components/{data.slug}">{data.title}</Link>
|
||||
</ListItem>
|
||||
{/each}
|
||||
</UnorderedList>
|
8
docs/src/routes/examples/Button.svelte
Normal file
|
@ -0,0 +1,8 @@
|
|||
<script>
|
||||
import { Button } from "carbon-components-svelte";
|
||||
</script>
|
||||
|
||||
<Button kind="primary">Primary button</Button>
|
||||
<Button kind="secondary">Secondary button</Button>
|
||||
<Button kind="tertiary">Tertiary button</Button>
|
||||
<Button kind="ghost">Ghost button</Button>
|
1
docs/src/routes/examples/_layout.svelte
Normal file
|
@ -0,0 +1 @@
|
|||
<slot />
|
|
@ -1,36 +1,10 @@
|
|||
<script>
|
||||
export let inline = false;
|
||||
|
||||
import { onMount, afterUpdate } from "svelte";
|
||||
import { Select, SelectItem } from "carbon-components-svelte";
|
||||
import { theme } from "../store";
|
||||
|
||||
onMount(() => {
|
||||
let currentTheme = localStorage.getItem("theme");
|
||||
|
||||
if (currentTheme) {
|
||||
theme.set(currentTheme);
|
||||
} else {
|
||||
if (
|
||||
window.matchMedia &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
) {
|
||||
theme.set("g90");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterUpdate(() => {
|
||||
localStorage.setItem("theme", $theme);
|
||||
document.documentElement.setAttribute("carbon-theme", $theme);
|
||||
});
|
||||
import components from "./components/_components";
|
||||
import { Link } from "carbon-components-svelte";
|
||||
</script>
|
||||
|
||||
<Select {inline} labelText="Theme" bind:selected={$theme}>
|
||||
<SelectItem value="white" text="White" />
|
||||
<SelectItem value="g10" text="Gray 10" />
|
||||
<SelectItem value="g90" text="Gray 90" />
|
||||
<SelectItem value="g100" text="Gray 100" />
|
||||
</Select>
|
||||
<!--
|
||||
<iframe width="900" height="500" src="about/" /> -->
|
||||
<h1>Welcome</h1>
|
||||
|
||||
{#each components as component}
|
||||
<Link href="examples/{component.title}">{component.title}</Link>
|
||||
{/each}
|
||||
|
|
|
@ -3,10 +3,9 @@ import polka from "polka";
|
|||
import * as sapper from "@sapper/server";
|
||||
|
||||
const { PORT, NODE_ENV } = process.env;
|
||||
const dev = NODE_ENV === "development";
|
||||
|
||||
polka()
|
||||
.use(sirv("static", { dev }), sapper.middleware())
|
||||
.use(sirv("static", { dev: NODE_ENV === "development" }), sapper.middleware())
|
||||
.listen(PORT, (err) => {
|
||||
if (err) console.log("error", err);
|
||||
});
|
||||
|
|
82
docs/src/service-worker.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { timestamp, files, shell, routes } from '@sapper/service-worker';
|
||||
|
||||
const ASSETS = `cache${timestamp}`;
|
||||
|
||||
// `shell` is an array of all the files generated by the bundler,
|
||||
// `files` is an array of everything in the `static` directory
|
||||
const to_cache = shell.concat(files);
|
||||
const cached = new Set(to_cache);
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.open(ASSETS)
|
||||
.then(cache => cache.addAll(to_cache))
|
||||
.then(() => {
|
||||
self.skipWaiting();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(
|
||||
caches.keys().then(async keys => {
|
||||
// delete old caches
|
||||
for (const key of keys) {
|
||||
if (key !== ASSETS) await caches.delete(key);
|
||||
}
|
||||
|
||||
self.clients.claim();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
if (event.request.method !== 'GET' || event.request.headers.has('range')) return;
|
||||
|
||||
const url = new URL(event.request.url);
|
||||
|
||||
// don't try to handle e.g. data: URIs
|
||||
if (!url.protocol.startsWith('http')) return;
|
||||
|
||||
// ignore dev server requests
|
||||
if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
|
||||
|
||||
// always serve static files and bundler-generated assets from cache
|
||||
if (url.host === self.location.host && cached.has(url.pathname)) {
|
||||
event.respondWith(caches.match(event.request));
|
||||
return;
|
||||
}
|
||||
|
||||
// for pages, you might want to serve a shell `service-worker-index.html` file,
|
||||
// which Sapper has generated for you. It's not right for every
|
||||
// app, but if it's right for yours then uncomment this section
|
||||
/*
|
||||
if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
|
||||
event.respondWith(caches.match('/service-worker-index.html'));
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
if (event.request.cache === 'only-if-cached') return;
|
||||
|
||||
// for everything else, try the network first, falling back to
|
||||
// cache if the user is offline. (If the pages never change, you
|
||||
// might prefer a cache-first approach to a network-first one.)
|
||||
event.respondWith(
|
||||
caches
|
||||
.open(`offline${timestamp}`)
|
||||
.then(async cache => {
|
||||
try {
|
||||
const response = await fetch(event.request);
|
||||
cache.put(event.request, response.clone());
|
||||
return response;
|
||||
} catch(err) {
|
||||
const response = await cache.match(event.request);
|
||||
if (response) return response;
|
||||
|
||||
throw err;
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
|
@ -1,5 +0,0 @@
|
|||
import { writable } from "svelte/store";
|
||||
|
||||
export const sideNavToggled = writable(false);
|
||||
export const appSwitcherToggled = writable(false);
|
||||
export const theme = writable("g10");
|
|
@ -1,42 +0,0 @@
|
|||
$feature-flags: (
|
||||
grid-columns-16: true,
|
||||
enable-css-custom-properties: true
|
||||
);
|
||||
|
||||
@import 'carbon-components/scss/globals/scss/_css--helpers.scss';
|
||||
@import 'carbon-components/scss/globals/scss/vendor/@carbon/elements/scss/themes/_mixins.scss';
|
||||
|
||||
:root {
|
||||
@include carbon--theme($carbon--theme--white, true);
|
||||
}
|
||||
|
||||
:root[carbon-theme='g10'] {
|
||||
@include carbon--theme($carbon--theme--g10, true);
|
||||
}
|
||||
|
||||
:root[carbon-theme='g90'] {
|
||||
@include carbon--theme($carbon--theme--g90, true);
|
||||
}
|
||||
|
||||
:root[carbon-theme='g100'] {
|
||||
@include carbon--theme($carbon--theme--g100, true);
|
||||
}
|
||||
|
||||
$css--font-face: true;
|
||||
$css--helpers: true;
|
||||
$css--body: true;
|
||||
$css--use-layer: true;
|
||||
$css--reset: true;
|
||||
$css--default-type: true;
|
||||
$css--plex: true;
|
||||
|
||||
@import '~carbon-components/scss/globals/scss/_css--reset.scss';
|
||||
@import '~carbon-components/scss/globals/scss/_css--font-face.scss';
|
||||
@import '~carbon-components/scss/globals/scss/_css--helpers.scss';
|
||||
@import '~carbon-components/scss/globals/scss/_css--body.scss';
|
||||
@import '~carbon-components/scss/globals/grid/_grid.scss';
|
||||
|
||||
@import '~carbon-components/scss/globals/scss/styles.scss';
|
||||
|
||||
/* @import '~carbon-components/scss/components/button/button';
|
||||
@import '~carbon-components/scss/components/select/select'; */
|
|
@ -3,12 +3,27 @@
|
|||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#161616" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="upgrade-insecure-requests"
|
||||
/>
|
||||
|
||||
%sapper.base%
|
||||
|
||||
<link rel="manifest" href="manifest.json" crossorigin="use-credentials" />
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/carbon-components/css/carbon-components.min.css"
|
||||
/>
|
||||
<title>Carbon Components Svelte</title>
|
||||
|
||||
%sapper.styles% %sapper.head%
|
||||
</head>
|
||||
<body>
|
||||
<div id="sapper">%sapper.html%</div>
|
||||
|
||||
%sapper.scripts%
|
||||
</body>
|
||||
</html>
|
||||
|
|
BIN
docs/static/favicon.png
vendored
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 7.2 KiB |
BIN
docs/static/logo-192.png
vendored
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 12 KiB |
BIN
docs/static/logo-512.png
vendored
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 40 KiB |
20
docs/static/manifest.json
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"background_color": "#161616",
|
||||
"theme_color": "#0f62fe",
|
||||
"name": "Carbon Components Svelte",
|
||||
"short_name": "Carbon Svelte",
|
||||
"display": "minimal-ui",
|
||||
"start_url": "/",
|
||||
"icons": [
|
||||
{
|
||||
"src": "logo-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "logo-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,18 +1,12 @@
|
|||
const webpack = require("webpack");
|
||||
const path = require("path");
|
||||
const config = require("@metonym/sapper/config/webpack.js");
|
||||
const config = require("sapper/config/webpack.js");
|
||||
const pkg = require("./package.json");
|
||||
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const AutoprefixerPlugin = require("autoprefixer");
|
||||
|
||||
const mode = process.env.NODE_ENV || "production";
|
||||
const mode = process.env.NODE_ENV;
|
||||
const dev = mode === "development";
|
||||
|
||||
const alias = {
|
||||
svelte: path.resolve("node_modules", "svelte"),
|
||||
sapper: path.resolve("node_modules", "@metonym/sapper"),
|
||||
};
|
||||
const alias = { svelte: path.resolve("node_modules", "svelte") };
|
||||
const extensions = [".mjs", ".js", ".json", ".svelte", ".html"];
|
||||
const mainFields = ["svelte", "module", "browser", "main"];
|
||||
|
||||
|
@ -27,39 +21,13 @@ module.exports = {
|
|||
test: /\.(svelte|html)$/,
|
||||
use: {
|
||||
loader: "svelte-loader",
|
||||
options: {
|
||||
dev,
|
||||
hydratable: true,
|
||||
hotReload: false, // pending https://github.com/sveltejs/svelte/issues/2377
|
||||
},
|
||||
options: { dev, hydratable: true, hotReload: false },
|
||||
},
|
||||
},
|
||||
{
|
||||
test: [/\.s[ac]ss$/i, /\.css$/],
|
||||
use: [
|
||||
!dev ? MiniCssExtractPlugin.loader : "style-loader",
|
||||
"css-loader",
|
||||
{
|
||||
loader: "postcss-loader",
|
||||
options: {
|
||||
plugins: [
|
||||
AutoprefixerPlugin({
|
||||
overrideBrowserslist: ["last 1 version", "ie >= 11"],
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
"sass-loader",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
mode,
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({ filename: "[name].[chunkhash].css" }),
|
||||
new OptimizeCssAssetsPlugin({}),
|
||||
// pending https://github.com/sveltejs/svelte/issues/2377
|
||||
// dev && new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
"process.browser": true,
|
||||
"process.env.NODE_ENV": JSON.stringify(mode),
|
||||
|
@ -85,7 +53,12 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
},
|
||||
mode,
|
||||
mode: process.env.NODE_ENV,
|
||||
performance: { hints: false },
|
||||
},
|
||||
serviceworker: {
|
||||
entry: config.serviceworker.entry(),
|
||||
output: config.serviceworker.output(),
|
||||
mode: process.env.NODE_ENV,
|
||||
},
|
||||
};
|
||||
|
|
3474
docs/yarn.lock
76
package.json
|
@ -10,73 +10,35 @@
|
|||
"start": "start-storybook -p 9090",
|
||||
"build": "build-storybook",
|
||||
"deploy": "gh-pages -d storybook-static",
|
||||
"test": "jest --coverage",
|
||||
"test:tdd": "jest --watch",
|
||||
"prepack": "rollup -c"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"dependencies": {
|
||||
"carbon-icons-svelte": "10.9.3",
|
||||
"carbon-icons-svelte": "^10.13.0",
|
||||
"flatpickr": "4.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.8.0",
|
||||
"@babel/preset-env": "^7.8.0",
|
||||
"@storybook/addon-knobs": "^5.3.1",
|
||||
"@storybook/addon-storysource": "^5.3.1",
|
||||
"@storybook/cli": "^5.3.1",
|
||||
"@storybook/svelte": "^5.3.1",
|
||||
"@testing-library/jest-dom": "^5.1.0",
|
||||
"@testing-library/svelte": "^1.11.0",
|
||||
"babel-jest": "^25.1.0",
|
||||
"@babel/core": "^7.10.5",
|
||||
"@babel/preset-env": "^7.10.4",
|
||||
"@rollup/plugin-commonjs": "^14.0.0",
|
||||
"@rollup/plugin-node-resolve": "^8.4.0",
|
||||
"@storybook/addon-knobs": "^5.3.19",
|
||||
"@storybook/addon-storysource": "^5.3.19",
|
||||
"@storybook/cli": "^5.3.19",
|
||||
"@storybook/svelte": "^5.3.19",
|
||||
"babel-loader": "^8.0.6",
|
||||
"gh-pages": "^2.2.0",
|
||||
"jest": "^25.1.0",
|
||||
"jest-transform-svelte": "^2.1.0",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"rollup": "^1.29.0",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"rollup-plugin-svelte": "^5.1.1",
|
||||
"rollup-plugin-terser": "^5.2.0",
|
||||
"svelte": "^3.23.0",
|
||||
"gh-pages": "^3.1.0",
|
||||
"rollup": "^2.22.1",
|
||||
"rollup-plugin-svelte": "^5.2.3",
|
||||
"rollup-plugin-terser": "^6.1.0",
|
||||
"svelte": "^3.24.0",
|
||||
"svelte-loader": "^2.13.6"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Eric Liu",
|
||||
"email": "eric.young.liu@ibm.com"
|
||||
},
|
||||
{
|
||||
"name": "Adan Ulloa",
|
||||
"email": "adanug@mx1.ibm.com"
|
||||
}
|
||||
],
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@babel/preset-env"
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
"^.+\\.svelte$": "jest-transform-svelte",
|
||||
"^.+\\.js$": "babel-jest"
|
||||
},
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"svelte"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"^carbon-icons-svelte*": "<rootDir>src/internal/Icon.stub.svelte"
|
||||
},
|
||||
"setupFilesAfterEnv": [
|
||||
"regenerator-runtime/runtime",
|
||||
"@testing-library/jest-dom/extend-expect"
|
||||
]
|
||||
},
|
||||
"resolutions": {
|
||||
"**/mem": ">=4.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ibm/carbon-components-svelte.git"
|
||||
|
@ -93,5 +55,15 @@
|
|||
"files": [
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Eric Liu",
|
||||
"email": "eric.young.liu@ibm.com"
|
||||
},
|
||||
{
|
||||
"name": "Adan Ulloa",
|
||||
"email": "adanug@mx1.ibm.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
5
palimpsest/.gitignore
vendored
|
@ -1,5 +0,0 @@
|
|||
/node_modules
|
||||
/build
|
||||
.DS_Store
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
|
@ -1,41 +0,0 @@
|
|||
# palimpsest
|
||||
|
||||
> pa·limp·sest
|
||||
|
||||
> writing material used one or more times after earlier writing has been erased – Merriam-Webster
|
||||
|
||||
The purpose of this app is to document and illustrate real world consumption of `carbon-components-svelte`.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This app uses a linked copy of `carbon-components-svelte` to expedite local development.
|
||||
|
||||
First, run the following commands at the root of `carbon-components-svelte/`:
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
yarn link
|
||||
```
|
||||
|
||||
Next, link the library to this folder.
|
||||
|
||||
```bash
|
||||
cd palimpsest
|
||||
yarn link "carbon-components-svelte"
|
||||
```
|
||||
|
||||
Finally, install this app's dependencies.
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Available Scripts
|
||||
|
||||
### `yarn start`
|
||||
|
||||
Runs the app in development mode with livereload enabled. Visit [http://localhost:8080](http://localhost:8080).
|
||||
|
||||
### `yarn build`
|
||||
|
||||
Builds the app in production mode.
|
|
@ -1,40 +0,0 @@
|
|||
{
|
||||
"name": "palimpsest",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "webpack-dev-server",
|
||||
"build": "NODE_ENV=production webpack"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.7.7",
|
||||
"@babel/preset-env": "^7.7.7",
|
||||
"autoprefixer": "^9.7.3",
|
||||
"carbon-components": "^10.9.0",
|
||||
"carbon-components-svelte": "../",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"clipboard-copy": "^3.1.0",
|
||||
"copy-webpack-plugin": "^5.0.5",
|
||||
"css-loader": "^3.2.0",
|
||||
"file-loader": "^5.0.2",
|
||||
"fuse.js": "^3.4.6",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"mini-css-extract-plugin": "^0.8.0",
|
||||
"node-sass": "^4.13.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"sass-loader": "^8.0.0",
|
||||
"style-loader": "^1.0.0",
|
||||
"svelte": "^3.12.1",
|
||||
"svelte-loader": "2.13.6",
|
||||
"svelte-spa-router": "^2.0.0",
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"webpack-dev-server": "^3.9.0"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@babel/preset-env"
|
||||
]
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 2.4 KiB |
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<link rel="icon" href="./favicon.png" />
|
||||
<title>Carbon Components Svelte</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
|
@ -1,11 +0,0 @@
|
|||
<script>
|
||||
import Router from 'svelte-spa-router';
|
||||
import Component from './components/Component';
|
||||
import Header from './components/Header.svelte';
|
||||
import Home from './components/Home.svelte';
|
||||
import SideNav from './components/SideNav.svelte';
|
||||
</script>
|
||||
|
||||
<Header />
|
||||
<SideNav />
|
||||
<Router routes={{ '/': Home, '/c': Component, '/c/*': Component }} />
|
Before Width: | Height: | Size: 7.9 KiB |
|
@ -1,109 +0,0 @@
|
|||
<script>
|
||||
export let href = undefined;
|
||||
export let kind = 'launch';
|
||||
export let iconLeft = undefined;
|
||||
export let iconRight = Launch20;
|
||||
|
||||
import Launch20 from 'carbon-icons-svelte/lib/Launch20';
|
||||
import ArrowRight20 from 'carbon-icons-svelte/lib/ArrowRight20';
|
||||
|
||||
$: iconRight = kind === 'link' ? ArrowRight20 : Launch20;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.link {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
border-right: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 671px) {
|
||||
.link {
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.link:focus {
|
||||
outline: 2px solid var(--cds-focus, #0f62fe);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
fill: var(--cds-icon-01);
|
||||
}
|
||||
|
||||
.icon--left {
|
||||
left: 1rem;
|
||||
}
|
||||
|
||||
.icon--right {
|
||||
right: 1rem;
|
||||
}
|
||||
|
||||
.bg {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
right: 1px;
|
||||
bottom: 1px;
|
||||
width: calc(100% - 1px);
|
||||
height: calc(100% - 1px);
|
||||
transition: 150ms cubic-bezier(0.2, 0, 0.38, 0.9);
|
||||
background-color: var(--cds-ui-01);
|
||||
}
|
||||
|
||||
.button-tile:hover .bg {
|
||||
background-color: var(--cds-ui-03);
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="button-tile bx--aspect-ratio bx--aspect-ratio--2x1">
|
||||
<div class="bx--aspect-ratio--object">
|
||||
{#if href}
|
||||
<a
|
||||
class="link"
|
||||
on:click
|
||||
target={kind === 'launch' ? '_blank' : undefined}
|
||||
rel={kind === 'launch' ? 'noopener noreferrer' : undefined}
|
||||
{href}>
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
{#if iconLeft}
|
||||
<div class="icon icon--left">
|
||||
<svelte:component this={iconLeft} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="icon icon--right">
|
||||
<svelte:component this={iconRight} />
|
||||
</div>
|
||||
</a>
|
||||
{:else}
|
||||
<div role="button" tabindex="0" class="link" on:click {href}>
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
{#if iconLeft}
|
||||
<div class="icon icon--left">
|
||||
<svelte:component this={iconLeft} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="icon icon--right">
|
||||
<svelte:component this={iconRight} />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="bg" />
|
||||
</div>
|
||||
</div>
|
|
@ -1,111 +0,0 @@
|
|||
<script context="module">
|
||||
import Accordion from '../carbon-components/Accordion';
|
||||
import CodeSnippet from '../carbon-components/CodeSnippet';
|
||||
|
||||
export const components = {
|
||||
Accordion,
|
||||
CodeSnippet
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { afterUpdate, setContext } from 'svelte';
|
||||
import { Tabs, Tab } from 'carbon-components-svelte';
|
||||
import { push, location } from 'svelte-spa-router';
|
||||
import Router from 'svelte-spa-router';
|
||||
import ComponentTab from './ComponentTab.svelte';
|
||||
|
||||
const prefix = '/c';
|
||||
const urls = [{ path: '' }, { path: '/API' }, { path: '/kitchen-sink' }];
|
||||
|
||||
let selected = 0;
|
||||
let component = undefined;
|
||||
let prevComponent = undefined;
|
||||
|
||||
setContext('Component', {
|
||||
set: name => {
|
||||
component = name;
|
||||
}
|
||||
});
|
||||
|
||||
afterUpdate(() => {
|
||||
if (component !== prevComponent && prevComponent !== undefined) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
prevComponent = component;
|
||||
});
|
||||
|
||||
$: baseUrl = component ? `#${prefix}/${component}` : $location;
|
||||
$: {
|
||||
switch (
|
||||
$location
|
||||
.split('/')
|
||||
.pop()
|
||||
.toLowerCase()
|
||||
) {
|
||||
case 'api':
|
||||
selected = 1;
|
||||
break;
|
||||
case 'kitchen-sink':
|
||||
selected = 2;
|
||||
break;
|
||||
default:
|
||||
selected = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
main {
|
||||
margin-top: 5rem;
|
||||
padding-left: 16rem;
|
||||
padding-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
main {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.bx--grid {
|
||||
max-width: 66rem;
|
||||
}
|
||||
|
||||
:global(body) {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
</style>
|
||||
|
||||
<main>
|
||||
<div class="bx--grid">
|
||||
<header class="bx--row">
|
||||
<div class="bx--col">
|
||||
<h1>{component}</h1>
|
||||
</div>
|
||||
</header>
|
||||
<div class="bx--row">
|
||||
<div class="bx--col bx--no-gutter">
|
||||
<Tabs
|
||||
type="container"
|
||||
bind:selected
|
||||
on:change={({ detail }) => {
|
||||
push(`${prefix}/${component}${urls[detail].path}`);
|
||||
}}>
|
||||
<Tab label="Preview" href={baseUrl} />
|
||||
<Tab label="API" href={`${baseUrl}/API`} />
|
||||
<!-- <Tab disabled label="Kitchen Sink" href={`${baseUrl}/kitchen-sink`} /> -->
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section class="bx--grid">
|
||||
<Router {prefix} routes={{ '/:name': ComponentTab, '/:name/:tab': ComponentTab }} />
|
||||
</section>
|
||||
</main>
|
|
@ -1,96 +0,0 @@
|
|||
<script>
|
||||
export let props = [];
|
||||
|
||||
import {
|
||||
StructuredList,
|
||||
StructuredListBody,
|
||||
StructuredListHead,
|
||||
StructuredListRow,
|
||||
StructuredListCell,
|
||||
Tag,
|
||||
CodeSnippet
|
||||
} from 'carbon-components-svelte';
|
||||
import copy from 'clipboard-copy';
|
||||
|
||||
const propTypeColor = {
|
||||
string: 'green',
|
||||
number: 'blue',
|
||||
boolean: 'purple'
|
||||
};
|
||||
|
||||
function formatValue(value) {
|
||||
return typeof value === 'string' ? `"${value}"` : value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.bx--row {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.values {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
:global(.value) {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
:global(.value:not(:first-of-type)) {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.separator {
|
||||
color: var(--cds-text-03);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bx--row">
|
||||
<StructuredList>
|
||||
<StructuredListHead>
|
||||
<StructuredListRow head>
|
||||
<StructuredListCell head>Prop</StructuredListCell>
|
||||
<StructuredListCell head>Type</StructuredListCell>
|
||||
<StructuredListCell head>Value</StructuredListCell>
|
||||
<StructuredListCell head>Description</StructuredListCell>
|
||||
</StructuredListRow>
|
||||
</StructuredListHead>
|
||||
<StructuredListBody>
|
||||
{#each props as prop, i (prop.name)}
|
||||
<StructuredListRow>
|
||||
<StructuredListCell noWrap>{prop.name}</StructuredListCell>
|
||||
<StructuredListCell noWrap>
|
||||
<Tag type={propTypeColor[prop.type]}>
|
||||
<code>{prop.type}</code>
|
||||
</Tag>
|
||||
</StructuredListCell>
|
||||
<StructuredListCell>
|
||||
<div class="values">
|
||||
{#each prop.value as value, j (value)}
|
||||
<CodeSnippet
|
||||
class="value"
|
||||
type="inline"
|
||||
code={formatValue(value)}
|
||||
on:click={() => {
|
||||
copy(formatValue(value));
|
||||
}} />
|
||||
{#if j < prop.value.length - 1}
|
||||
<span class="separator">|</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{#if prop.defaultValue}
|
||||
<div style="margin-top: .75rem">
|
||||
<strong>Default:</strong>
|
||||
<code>{formatValue(prop.defaultValue.value)}</code>
|
||||
</div>
|
||||
{/if}
|
||||
</StructuredListCell>
|
||||
<StructuredListCell>
|
||||
{@html prop.description}
|
||||
</StructuredListCell>
|
||||
</StructuredListRow>
|
||||
{/each}
|
||||
</StructuredListBody>
|
||||
</StructuredList>
|
||||
</div>
|
|
@ -1,110 +0,0 @@
|
|||
<script>
|
||||
export let minHeight = '11.5rem';
|
||||
export let light = false;
|
||||
export let code = '';
|
||||
|
||||
import copy from 'clipboard-copy';
|
||||
import { CodeSnippet } from 'carbon-components-svelte';
|
||||
import { theme } from '../../store';
|
||||
|
||||
$: code = code.trim().replace(/< \//g, '</');
|
||||
$: light = light && ['white', 'g10'].includes($theme);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.preview {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border: 1px solid var(--cds-ui-03);
|
||||
}
|
||||
|
||||
.preview.light {
|
||||
background-color: var(--cds-ui-01);
|
||||
}
|
||||
|
||||
.grid {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.grid--row {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.grid--col:not(:last-of-type) {
|
||||
border-right: 1px dashed var(--cds-ui-03);
|
||||
}
|
||||
|
||||
.grid--col.light {
|
||||
background-color: var(--cds-ui-01);
|
||||
}
|
||||
|
||||
.grid--col--outer {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.grid--col--inner {
|
||||
flex: 1;
|
||||
background-color: var(--cds-ui-background);
|
||||
}
|
||||
|
||||
.grid--col--inner {
|
||||
border-left: 1px dashed var(--cds-ui-03);
|
||||
border-right: 1px dashed var(--cds-ui-03);
|
||||
}
|
||||
|
||||
.grid--col--inner.light {
|
||||
background-color: var(--cds-ui-01);
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: inline-flex;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
min-height: 9rem;
|
||||
padding: 2rem 0 2rem 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="preview bx--row" class:light>
|
||||
<div class="grid">
|
||||
<div class="grid--row">
|
||||
{#each Array.from({ length: 8 }, (_, i) => i) as item, i (item)}
|
||||
<div class="grid--col bx--col" class:light>
|
||||
<div class="grid--col--outer">
|
||||
<div class="grid--col--inner" class:light />
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div class="bx--col bx--no-gutter--left">
|
||||
<div class="wrapper" style={`min-height: ${minHeight}`}>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bx--row">
|
||||
<div class="bx--col-lg-4">
|
||||
<h3>Props</h3>
|
||||
<slot name="props" />
|
||||
</div>
|
||||
<div class="bx--col">
|
||||
<h3>Code</h3>
|
||||
<CodeSnippet type="multi" on:click={() => copy(code)} {code} />
|
||||
<slot name="code" />
|
||||
</div>
|
||||
</div>
|
|
@ -1,23 +0,0 @@
|
|||
<script>
|
||||
export let params = {};
|
||||
|
||||
import { getContext } from 'svelte';
|
||||
import { components } from './Component.svelte';
|
||||
|
||||
const { set } = getContext('Component');
|
||||
|
||||
const paramMap = {
|
||||
Preview: 'Preview',
|
||||
API: 'API',
|
||||
'kitchen-sink': 'KitchenSink'
|
||||
};
|
||||
|
||||
$: tabName = params.tab || 'Preview';
|
||||
$: tab = paramMap[tabName];
|
||||
$: {
|
||||
set(params.name);
|
||||
document.title = `${params.name} · ${tabName}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:component this={components[params.name][tab]} />
|
|
@ -1,5 +0,0 @@
|
|||
import Component from './Component.svelte';
|
||||
|
||||
export default Component;
|
||||
export { default as ComponentPreview } from './ComponentPreview.svelte';
|
||||
export { default as ComponentAPI } from './ComponentAPI.svelte';
|
|
@ -1,142 +0,0 @@
|
|||
<script>
|
||||
import { link } from 'svelte-spa-router';
|
||||
import { Icon } from 'carbon-components-svelte';
|
||||
import AppSwitcher20 from 'carbon-icons-svelte/lib/AppSwitcher20';
|
||||
import Menu20 from 'carbon-icons-svelte/lib/Menu20';
|
||||
import Close20 from 'carbon-icons-svelte/lib/Close20';
|
||||
import ThemePicker from '../components/ThemePicker.svelte';
|
||||
import { sideNavToggled, appSwitcherToggled } from '../store';
|
||||
</script>
|
||||
|
||||
<style>
|
||||
header {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
padding: 0 1rem;
|
||||
background-color: var(--cds-ui-01);
|
||||
border-bottom: 1px solid var(--cds-ui-03);
|
||||
}
|
||||
|
||||
.app-switcher {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
top: 2.5rem;
|
||||
right: 0;
|
||||
width: 16rem;
|
||||
height: calc(100% - 2.5rem);
|
||||
padding: 1rem;
|
||||
background-color: var(--cds-ui-01);
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.app-switcher {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.app-switcher.toggled {
|
||||
transform: translateX(0);
|
||||
transition: transform 110ms cubic-bezier(0.2, 0, 1, 0.9);
|
||||
will-change: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
margin-left: -1rem;
|
||||
margin-right: 0.5rem;
|
||||
background: none;
|
||||
border: 0;
|
||||
fill: var(--cds-ui-05);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu--right {
|
||||
margin-left: auto;
|
||||
margin-right: -1rem;
|
||||
}
|
||||
|
||||
.menu:focus {
|
||||
outline: 2px solid var(--cds-focus, #0f62fe);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bx--link {
|
||||
font-size: 1rem;
|
||||
color: var(--cds-text-01);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bx--link:hover {
|
||||
color: var(--cds-text-01);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.menu {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.theme {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<header>
|
||||
<nav>
|
||||
<button
|
||||
class="menu"
|
||||
on:click={() => {
|
||||
sideNavToggled.set(!$sideNavToggled);
|
||||
appSwitcherToggled.set(false);
|
||||
}}>
|
||||
<Icon render={$sideNavToggled ? Close20 : Menu20} />
|
||||
</button>
|
||||
<a
|
||||
class="bx--link"
|
||||
href="/"
|
||||
use:link
|
||||
on:click={() => {
|
||||
if ($sideNavToggled || $appSwitcherToggled) {
|
||||
sideNavToggled.set(false);
|
||||
appSwitcherToggled.set(false);
|
||||
}
|
||||
window.scrollTo(0, 0);
|
||||
}}>
|
||||
Carbon Components
|
||||
<strong>Svelte</strong>
|
||||
</a>
|
||||
</nav>
|
||||
<div class="theme">
|
||||
<ThemePicker inline />
|
||||
</div>
|
||||
<button
|
||||
class="menu menu--right"
|
||||
on:click={() => {
|
||||
appSwitcherToggled.set(!$appSwitcherToggled);
|
||||
sideNavToggled.set(false);
|
||||
}}>
|
||||
<Icon render={$appSwitcherToggled ? Close20 : AppSwitcher20} />
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="app-switcher" class:toggled={$appSwitcherToggled}>
|
||||
<ThemePicker />
|
||||
</div>
|
|
@ -1,101 +0,0 @@
|
|||
<script>
|
||||
import LogoGithub32 from 'carbon-icons-svelte/lib/LogoGithub32';
|
||||
import Logo from '../assets/logo.png';
|
||||
import ButtonTile from './ButtonTile.svelte';
|
||||
|
||||
$: {
|
||||
document.title = 'Carbon Components Svelte';
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
main {
|
||||
margin-top: 2.5rem;
|
||||
padding-left: 16rem;
|
||||
padding-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
main {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.banner {
|
||||
background: var(--cds-ui-01);
|
||||
padding: 2.5rem 0 1.5rem;
|
||||
}
|
||||
|
||||
.bx--grid {
|
||||
max-width: 66rem;
|
||||
}
|
||||
|
||||
.logo {
|
||||
max-width: 4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 2rem;
|
||||
font-size: 2rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h1 span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 2.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<main>
|
||||
<div class="banner">
|
||||
<div class="bx--grid">
|
||||
<div class="bx--row">
|
||||
<div class="bx--col">
|
||||
<img src={Logo} alt="Logo" class="logo" />
|
||||
<h1>
|
||||
<span>
|
||||
<strong>Carbon</strong>
|
||||
</span>
|
||||
<span>
|
||||
<strong>Components</strong>
|
||||
</span>
|
||||
<span>
|
||||
<strong>Svelte</strong>
|
||||
</span>
|
||||
</h1>
|
||||
<h3>The Carbon Design System implemented in Svelte.</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bx--grid">
|
||||
<div class="bx--row">
|
||||
<div class="bx--col">
|
||||
<h3>Packages</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bx--row bx--no-gutter">
|
||||
<div class="bx--no-gutter-sm bx--col-md-4 bx--col-lg-4">
|
||||
<ButtonTile iconLeft={LogoGithub32} href="https://github.com/IBM/carbon-components-svelte">
|
||||
Carbon Components Svelte
|
||||
</ButtonTile>
|
||||
</div>
|
||||
<div class="bx--no-gutter-sm bx--col-md-4 bx--col-lg-4">
|
||||
<ButtonTile iconLeft={LogoGithub32} href="https://github.com/IBM/carbon-icons-svelte">
|
||||
Carbon Icons Svelte
|
||||
</ButtonTile>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bx--row">
|
||||
<div class="bx--col">
|
||||
<h3>Components</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
|
@ -1,147 +0,0 @@
|
|||
<script>
|
||||
import { link, location } from 'svelte-spa-router';
|
||||
import { Search } from 'carbon-components-svelte';
|
||||
import Fuse from 'fuse.js';
|
||||
import components from '../data/component-registry';
|
||||
import { sideNavToggled, appSwitcherToggled } from '../store';
|
||||
|
||||
const fuse = new Fuse(components, { shouldSort: false, threshold: 0.33, keys: ['name'] });
|
||||
|
||||
let value = '';
|
||||
|
||||
$: results = value.length > 1 ? fuse.search(value) : components;
|
||||
|
||||
$: {
|
||||
if ($sideNavToggled || $appSwitcherToggled) {
|
||||
document.body.classList.add('hidden');
|
||||
} else {
|
||||
document.body.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:global(body.hidden) {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
nav {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
top: 2.5rem;
|
||||
left: 0;
|
||||
width: 16rem;
|
||||
height: calc(100% - 2.5rem);
|
||||
background-color: var(--cds-ui-01);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
nav {
|
||||
transform: translateX(-100%);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
nav.toggled {
|
||||
transform: translateX(0);
|
||||
transition: transform 110ms cubic-bezier(0.2, 0, 1, 0.9);
|
||||
will-change: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
z-index: 9998;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--cds-overlay-01);
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bx--link {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0.375rem 1rem;
|
||||
color: var(--cds-text-01);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.bx--link:focus {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bx--link:hover {
|
||||
background-color: var(--cds-ui-03);
|
||||
color: var(--cds-text-01);
|
||||
}
|
||||
|
||||
.bx--link.current {
|
||||
background-color: var(--cds-ui-03);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.bx--link.current:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0.25rem;
|
||||
height: 100%;
|
||||
background-color: var(--cds-interactive-01);
|
||||
}
|
||||
</style>
|
||||
|
||||
<svelte:window
|
||||
on:resize={() => {
|
||||
if (($sideNavToggled || $appSwitcherToggled) && window.matchMedia('(min-width: 768px)').matches) {
|
||||
sideNavToggled.set(false);
|
||||
appSwitcherToggled.set(false);
|
||||
}
|
||||
}} />
|
||||
|
||||
<nav class:toggled={$sideNavToggled}>
|
||||
<Search
|
||||
small
|
||||
id="search-components"
|
||||
labelText="Components"
|
||||
placeholder="Search components..."
|
||||
bind:value />
|
||||
<ul>
|
||||
{#each results as { name }, i (name)}
|
||||
<li>
|
||||
<a
|
||||
on:click={() => {
|
||||
if ($sideNavToggled) {
|
||||
sideNavToggled.set(false);
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
}}
|
||||
class="bx--link"
|
||||
class:current={$location.includes(`/c/${name}`)}
|
||||
href={`/c/${name}`}
|
||||
use:link>
|
||||
{name}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{#if $sideNavToggled || $appSwitcherToggled}
|
||||
<div
|
||||
class="overlay"
|
||||
on:click={() => {
|
||||
sideNavToggled.set(false);
|
||||
appSwitcherToggled.set(false);
|
||||
}} />
|
||||
{/if}
|
|
@ -1,31 +0,0 @@
|
|||
<script>
|
||||
export let inline = false;
|
||||
|
||||
import { onMount, afterUpdate } from 'svelte';
|
||||
import { Select, SelectItem } from 'carbon-components-svelte';
|
||||
import { theme } from '../store';
|
||||
|
||||
onMount(() => {
|
||||
let currentTheme = localStorage.getItem('theme');
|
||||
|
||||
if (currentTheme) {
|
||||
theme.set(currentTheme);
|
||||
} else {
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
theme.set('g90');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterUpdate(() => {
|
||||
localStorage.setItem('theme', $theme);
|
||||
document.documentElement.setAttribute('carbon-theme', $theme);
|
||||
});
|
||||
</script>
|
||||
|
||||
<Select {inline} labelText="Theme" bind:selected={$theme}>
|
||||
<SelectItem value="white" text="White" />
|
||||
<SelectItem value="g10" text="Gray 10" />
|
||||
<SelectItem value="g90" text="Gray 90" />
|
||||
<SelectItem value="g100" text="Gray 100" />
|
||||
</Select>
|
|
@ -1,40 +0,0 @@
|
|||
<script>
|
||||
import { ComponentAPI } from '../../Component';
|
||||
|
||||
const props = [
|
||||
{
|
||||
name: 'type',
|
||||
type: 'string',
|
||||
required: true,
|
||||
value: ['inline', 'single', 'multi'],
|
||||
defaultValue: { value: 'single' },
|
||||
description: `
|
||||
<div>
|
||||
<strong>Inline</strong> An inline <code>CodeSnippet</code> contains
|
||||
</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'light',
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
value: [],
|
||||
defaultValue: { value: false },
|
||||
description: `
|
||||
<div>Light variant</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'code',
|
||||
type: 'string',
|
||||
required: true,
|
||||
value: [],
|
||||
defaultValue: { value: undefined },
|
||||
description: `
|
||||
<div>Light variant</div>
|
||||
`
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<ComponentAPI {props} />
|
|
@ -1,61 +0,0 @@
|
|||
<script>
|
||||
import {
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
ToggleSmall,
|
||||
NumberInput,
|
||||
FormGroup
|
||||
} from 'carbon-components-svelte';
|
||||
import { ComponentPreview } from '../../Component';
|
||||
|
||||
$: items = [1, 2, 3, 4].map(id => ({ id, open: false }));
|
||||
|
||||
$: props = {
|
||||
count: 4,
|
||||
open: false,
|
||||
skeleton: false
|
||||
};
|
||||
|
||||
$: if (props.skeleton) {
|
||||
items = items.map(_ => ({ ..._, open: false }));
|
||||
}
|
||||
|
||||
$: code = `
|
||||
<script>
|
||||
import { Accordion, AccordionItem } from 'carbon-components-svelte';
|
||||
< /script>
|
||||
|
||||
<Accordion${props.skeleton ? ' skeleton' : ''}${props.skeleton ? ` count={${props.count}}` : ''}${
|
||||
props.open ? ` open` : ''
|
||||
}>
|
||||
${items
|
||||
.map(item => {
|
||||
return ` <AccordionItem title="Item ${item.id}"${item.open ? ' open' : ''}>Item ${
|
||||
item.id
|
||||
} content</AccordionItem>`;
|
||||
})
|
||||
.join('\n')}
|
||||
</Accordion>
|
||||
`;
|
||||
</script>
|
||||
|
||||
<ComponentPreview {code} minHeight="16rem">
|
||||
<Accordion {...props}>
|
||||
{#each items as { id }, i (id)}
|
||||
<AccordionItem title={`Item ${id}`} bind:open={items[i].open}>
|
||||
Item {id} content
|
||||
</AccordionItem>
|
||||
{/each}
|
||||
</Accordion>
|
||||
<div slot="props">
|
||||
<FormGroup legendText="Skeleton">
|
||||
<ToggleSmall id="toggle-skeleton" bind:toggled={props.skeleton} />
|
||||
</FormGroup>
|
||||
<FormGroup legendText="Skeleton row count">
|
||||
<NumberInput disabled={!props.skeleton} bind:value={props.count} />
|
||||
</FormGroup>
|
||||
<FormGroup legendText="Skeleton first item open">
|
||||
<ToggleSmall id="toggle-open" disabled={!props.skeleton} bind:toggled={props.open} />
|
||||
</FormGroup>
|
||||
</div>
|
||||
</ComponentPreview>
|
|
@ -1,11 +0,0 @@
|
|||
import Preview from './Preview.svelte';
|
||||
import API from './API.svelte';
|
||||
import KitchenSink from './KitchenSink.svelte';
|
||||
|
||||
const tabs = {
|
||||
Preview,
|
||||
API,
|
||||
KitchenSink
|
||||
};
|
||||
|
||||
export default tabs;
|
|
@ -1,40 +0,0 @@
|
|||
<script>
|
||||
import { ComponentAPI } from '../../Component';
|
||||
|
||||
const props = [
|
||||
{
|
||||
name: 'type',
|
||||
type: 'string',
|
||||
required: true,
|
||||
value: ['inline', 'single', 'multi'],
|
||||
defaultValue: { value: 'single' },
|
||||
description: `
|
||||
<div>
|
||||
<strong>Inline</strong> An inline <code>CodeSnippet</code> contains
|
||||
</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'light',
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
value: [],
|
||||
defaultValue: { value: false },
|
||||
description: `
|
||||
<div>Light variant</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'code',
|
||||
type: 'string',
|
||||
required: true,
|
||||
value: [],
|
||||
defaultValue: { value: undefined },
|
||||
description: `
|
||||
<div>Light variant</div>
|
||||
`
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<ComponentAPI {props} />
|
|
@ -1,72 +0,0 @@
|
|||
<script>
|
||||
import {
|
||||
TextArea,
|
||||
TextInput,
|
||||
ToggleSmall,
|
||||
CodeSnippet,
|
||||
FormGroup,
|
||||
RadioButtonGroup,
|
||||
RadioButton
|
||||
} from 'carbon-components-svelte';
|
||||
import { ComponentPreview } from '../../Component';
|
||||
|
||||
$: props = {
|
||||
code: `
|
||||
This is a <CodeSnippet />
|
||||
`.trim(),
|
||||
light: false,
|
||||
type: 'single',
|
||||
skeleton: false,
|
||||
feedback: 'Copied!'
|
||||
};
|
||||
|
||||
$: code = `
|
||||
<script>
|
||||
import { CodeSnippet } from 'carbon-components-svelte';
|
||||
|
||||
$: code = \`${props.code}\`;
|
||||
< /script>
|
||||
|
||||
<CodeSnippet type="${props.type}"${props.light ? ' light' : ''} {code}${
|
||||
props.skeleton ? ' skeleton' : ''
|
||||
} feedback="${props.feedback}" />
|
||||
`;
|
||||
|
||||
$: if (props.type === 'inline') {
|
||||
props.skeleton = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<ComponentPreview light={props.light} {code}>
|
||||
<div>
|
||||
<CodeSnippet {...props} />
|
||||
</div>
|
||||
<div slot="props">
|
||||
<FormGroup legendText="Type">
|
||||
<RadioButtonGroup legend="Type" bind:selected={props.type}>
|
||||
<RadioButton value="inline" id="inline" labelText="inline" />
|
||||
<RadioButton value="single" id="single" labelText="single" />
|
||||
<RadioButton value="multi" id="multi" labelText="multi" />
|
||||
</RadioButtonGroup>
|
||||
</FormGroup>
|
||||
<FormGroup legendText="Light variant">
|
||||
<ToggleSmall id="toggle-light" bind:toggled={props.light} />
|
||||
</FormGroup>
|
||||
<FormGroup legendText="Code">
|
||||
{#if props.type === 'multi'}
|
||||
<TextArea bind:value={props.code} />
|
||||
{:else}
|
||||
<TextInput bind:value={props.code} />
|
||||
{/if}
|
||||
</FormGroup>
|
||||
<FormGroup legendText="Skeleton">
|
||||
<ToggleSmall
|
||||
id="toggle-skeleton"
|
||||
disabled={props.type === 'inline'}
|
||||
bind:toggled={props.skeleton} />
|
||||
</FormGroup>
|
||||
<FormGroup legendText="Feedback text">
|
||||
<TextInput placeholder="Enter text" bind:value={props.feedback} />
|
||||
</FormGroup>
|
||||
</div>
|
||||
</ComponentPreview>
|
|
@ -1,11 +0,0 @@
|
|||
import Preview from './Preview.svelte';
|
||||
import API from './API.svelte';
|
||||
import KitchenSink from './KitchenSink.svelte';
|
||||
|
||||
const tabs = {
|
||||
Preview,
|
||||
API,
|
||||
KitchenSink
|
||||
};
|
||||
|
||||
export default tabs;
|
|
@ -1,50 +0,0 @@
|
|||
const components = [
|
||||
{ name: 'Accordion' },
|
||||
{ name: 'Breadcrumb' },
|
||||
{ name: 'Button' },
|
||||
{ name: 'Checkbox' },
|
||||
{ name: 'CodeSnippet' },
|
||||
{ name: 'ComboBox' },
|
||||
{ name: 'ComposedModal' },
|
||||
{ name: 'ContentSwitcher' },
|
||||
{ name: 'CopyButton' },
|
||||
{ name: 'DataTable' },
|
||||
{ name: 'DatePicker' },
|
||||
{ name: 'Dropdown' },
|
||||
{ name: 'FileUploader' },
|
||||
{ name: 'Form' },
|
||||
{ name: 'Icon' },
|
||||
{ name: 'InlineLoading' },
|
||||
{ name: 'Link' },
|
||||
{ name: 'Loading' },
|
||||
{ name: 'Modal' },
|
||||
{ name: 'MultiSelect' },
|
||||
{ name: 'Notification' },
|
||||
{ name: 'NumberInput' },
|
||||
{ name: 'OrderedList' },
|
||||
{ name: 'OverflowMenu' },
|
||||
{ name: 'Pagination' },
|
||||
{ name: 'ProgressIndicator' },
|
||||
{ name: 'RadioButton' },
|
||||
{ name: 'RadioButtonGroup' },
|
||||
{ name: 'Search' },
|
||||
{ name: 'Select' },
|
||||
{ name: 'SkeletonPlaceholder' },
|
||||
{ name: 'SkeletonText' },
|
||||
{ name: 'Slider' },
|
||||
{ name: 'StructuredList' },
|
||||
{ name: 'Tabs' },
|
||||
{ name: 'Tag' },
|
||||
{ name: 'TextArea' },
|
||||
{ name: 'TextInput' },
|
||||
{ name: 'Tile' },
|
||||
{ name: 'TimePicker' },
|
||||
{ name: 'Toggle' },
|
||||
{ name: 'ToggleSmall' },
|
||||
{ name: 'Tooltip' },
|
||||
{ name: 'TooltipDefinition' },
|
||||
{ name: 'TooltipIcon' },
|
||||
{ name: 'UnorderedList' }
|
||||
];
|
||||
|
||||
export default components;
|
|
@ -1,6 +0,0 @@
|
|||
import './style.scss';
|
||||
import App from './App.svelte';
|
||||
|
||||
const app = new App({ target: document.body });
|
||||
|
||||
export default app;
|
|
@ -1,5 +0,0 @@
|
|||
import { writable } from 'svelte/store';
|
||||
|
||||
export const sideNavToggled = writable(false);
|
||||
export const appSwitcherToggled = writable(false);
|
||||
export const theme = writable('g10');
|
|
@ -1,37 +0,0 @@
|
|||
$feature-flags: (
|
||||
enable-css-custom-properties: true
|
||||
);
|
||||
|
||||
@import 'carbon-components/scss/globals/scss/_css--helpers.scss';
|
||||
@import 'carbon-components/scss/globals/scss/vendor/@carbon/elements/scss/themes/_mixins.scss';
|
||||
|
||||
:root {
|
||||
@include carbon--theme($carbon--theme--white, true);
|
||||
}
|
||||
|
||||
:root[carbon-theme='g10'] {
|
||||
@include carbon--theme($carbon--theme--g10, true);
|
||||
}
|
||||
|
||||
:root[carbon-theme='g90'] {
|
||||
@include carbon--theme($carbon--theme--g90, true);
|
||||
}
|
||||
|
||||
:root[carbon-theme='g100'] {
|
||||
@include carbon--theme($carbon--theme--g100, true);
|
||||
}
|
||||
|
||||
$css--font-face: true;
|
||||
$css--helpers: true;
|
||||
$css--body: true;
|
||||
$css--use-layer: true;
|
||||
$css--reset: true;
|
||||
$css--default-type: true;
|
||||
$css--plex: true;
|
||||
|
||||
@import 'carbon-components/scss/globals/scss/_css--reset.scss';
|
||||
@import 'carbon-components/scss/globals/scss/_css--font-face.scss';
|
||||
@import 'carbon-components/scss/globals/scss/_css--helpers.scss';
|
||||
@import 'carbon-components/scss/globals/scss/_css--body.scss';
|
||||
@import 'carbon-components/scss/globals/grid/_grid.scss';
|
||||
@import 'carbon-components/scss/globals/scss/styles.scss';
|
|
@ -1,78 +0,0 @@
|
|||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const path = require('path');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
|
||||
const NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
const IS_PROD = NODE_ENV === 'production';
|
||||
|
||||
module.exports = {
|
||||
stats: 'errors-only',
|
||||
devtool: IS_PROD ? false : 'cheap-eval-source-map',
|
||||
entry: { bundle: ['./src/index.js'] },
|
||||
resolve: {
|
||||
alias: { svelte: path.resolve('node_modules', 'svelte') },
|
||||
extensions: ['.mjs', '.js', '.svelte'],
|
||||
mainFields: ['svelte', 'browser', 'module', 'main']
|
||||
},
|
||||
output: { path: path.resolve(__dirname, 'build'), filename: '[name].[chunkhash].js' },
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.svelte$/,
|
||||
use: { loader: 'svelte-loader', options: { emitCss: true, hotReload: true } }
|
||||
},
|
||||
{
|
||||
test: [/\.s[ac]ss$/i, /\.css$/],
|
||||
use: [
|
||||
IS_PROD ? MiniCssExtractPlugin.loader : 'style-loader',
|
||||
'css-loader',
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
plugins: [
|
||||
require('autoprefixer')({
|
||||
overrideBrowserslist: ['last 1 version', 'ie >= 11']
|
||||
})
|
||||
]
|
||||
}
|
||||
},
|
||||
'sass-loader'
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|svg)$/i,
|
||||
use: [{ loader: 'file-loader' }]
|
||||
}
|
||||
]
|
||||
},
|
||||
mode: NODE_ENV,
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new CopyPlugin([{ from: 'public' }]),
|
||||
new MiniCssExtractPlugin({ filename: '[name].[chunkhash].css' }),
|
||||
new OptimizeCssAssetsPlugin({}),
|
||||
new HtmlWebpackPlugin(
|
||||
Object.assign(
|
||||
{},
|
||||
{ inject: true, template: 'public/index.html' },
|
||||
IS_PROD
|
||||
? {
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyElements: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyURLs: true
|
||||
}
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
)
|
||||
]
|
||||
};
|
6981
palimpsest/yarn.lock
|
@ -1,7 +1,7 @@
|
|||
import { terser } from "rollup-plugin-terser";
|
||||
import pkg from "./package.json";
|
||||
import resolve from "rollup-plugin-node-resolve";
|
||||
import commonjs from "rollup-plugin-commonjs";
|
||||
import resolve from "@rollup/plugin-node-resolve";
|
||||
import commonjs from "@rollup/plugin-commonjs";
|
||||
import svelte from "rollup-plugin-svelte";
|
||||
|
||||
export default ["es", "umd"].map((format) => {
|
||||
|
|
40
src/Accordion/Accordion.Skeleton.svelte
Normal file
|
@ -0,0 +1,40 @@
|
|||
<script>
|
||||
export let count = 4;
|
||||
export let open = true;
|
||||
|
||||
import ChevronRight16 from "carbon-icons-svelte/lib/ChevronRight16";
|
||||
import { SkeletonText } from "../SkeletonText";
|
||||
</script>
|
||||
|
||||
<ul
|
||||
class:bx--accordion={true}
|
||||
class:bx--skeleton={true}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave>
|
||||
{#if open}
|
||||
<li
|
||||
class:bx--accordion__item={true}
|
||||
class:bx--accordion__item--active={true}>
|
||||
<span class:bx--accordion__heading={true}>
|
||||
<ChevronRight16 class="bx--accordion__arrow" />
|
||||
<SkeletonText class="bx--accordion__title" />
|
||||
</span>
|
||||
<div class="bx--accordion__content">
|
||||
<SkeletonText width="90%" />
|
||||
<SkeletonText width="80%" />
|
||||
<SkeletonText width="95%" />
|
||||
</div>
|
||||
</li>
|
||||
{/if}
|
||||
{#each Array.from({ length: open ? count - 1 : count }, (_, i) => i) as item, i (item)}
|
||||
<li class="bx--accordion__item">
|
||||
<span class="bx--accordion__heading">
|
||||
<ChevronRight16 class="bx--accordion__arrow" />
|
||||
<SkeletonText class="bx--accordion__title" />
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
56
src/Accordion/Accordion.Story.svelte
Normal file
|
@ -0,0 +1,56 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
export let title = undefined;
|
||||
export let open = undefined;
|
||||
export let count = undefined;
|
||||
|
||||
import Accordion from "./Accordion.svelte";
|
||||
import AccordionItem from "./AccordionItem.svelte";
|
||||
import AccordionSkeleton from "./Accordion.Skeleton.svelte";
|
||||
</script>
|
||||
|
||||
{#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}
|
32
src/Accordion/Accordion.stories.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
import {
|
||||
withKnobs,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
select,
|
||||
} from "@storybook/addon-knobs";
|
||||
import Component from "./Accordion.Story.svelte";
|
||||
|
||||
export default { title: "Accordion", decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
align: select(
|
||||
"Accordion heading alignment (align)",
|
||||
["start", "end"],
|
||||
"end"
|
||||
),
|
||||
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),
|
||||
},
|
||||
});
|
21
src/Accordion/Accordion.svelte
Normal file
|
@ -0,0 +1,21 @@
|
|||
<script>
|
||||
export let align = "end"; // "start" | "end"
|
||||
export let skeleton = false;
|
||||
|
||||
import AccordionSkeleton from "./Accordion.Skeleton.svelte";
|
||||
</script>
|
||||
|
||||
{#if skeleton}
|
||||
<AccordionSkeleton {...$$restProps} />
|
||||
{:else}
|
||||
<ul
|
||||
class:bx--accordion={true}
|
||||
class="bx--accordion--{align}"
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave>
|
||||
<slot />
|
||||
</ul>
|
||||
{/if}
|
47
src/Accordion/AccordionItem.svelte
Normal file
|
@ -0,0 +1,47 @@
|
|||
<script>
|
||||
export let title = "title";
|
||||
export let open = false;
|
||||
export let iconDescription = "Expand/Collapse";
|
||||
|
||||
import ChevronRight16 from "carbon-icons-svelte/lib/ChevronRight16";
|
||||
|
||||
$: animation = undefined;
|
||||
</script>
|
||||
|
||||
<li
|
||||
class:bx--accordion__item={true}
|
||||
class:bx--accordion__item--active={open}
|
||||
class="bx--accordion__item--${animation}"
|
||||
{...$$restProps}
|
||||
on:animationend
|
||||
on:animationend={() => {
|
||||
animation = undefined;
|
||||
}}>
|
||||
<button
|
||||
type="button"
|
||||
class:bx--accordion__heading={true}
|
||||
title={iconDescription}
|
||||
aria-expanded={open}
|
||||
on:click
|
||||
on:click={() => {
|
||||
open = !open;
|
||||
animation = open ? 'expanding' : 'collapsing';
|
||||
}}
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
on:keydown
|
||||
on:keydown={({ key }) => {
|
||||
if (open && key === 'Escape') {
|
||||
open = false;
|
||||
}
|
||||
}}>
|
||||
<ChevronRight16 class="bx--accordion__arrow" aria-label={iconDescription} />
|
||||
<div class="bx--accordion__title">
|
||||
<slot name="title">{title}</slot>
|
||||
</div>
|
||||
</button>
|
||||
<div class="bx--accordion__content">
|
||||
<slot />
|
||||
</div>
|
||||
</li>
|
3
src/Accordion/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
export { default as Accordion } from "./Accordion.svelte";
|
||||
export { default as AccordionItem } from "./AccordionItem.svelte";
|
||||
export { default as AccordionSkeleton } from "./Accordion.Skeleton.svelte";
|
14
src/Breadcrumb/Breadcrumb.Skeleton.svelte
Normal file
|
@ -0,0 +1,14 @@
|
|||
<div
|
||||
class:bx--breadcrumb={true}
|
||||
class:bx--skeleton={true}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave>
|
||||
{#each [0, 1, 2] as item, i (item)}
|
||||
<div class:bx--breadcrumb-item={true}>
|
||||
<span class:bx--link={true}> </span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
36
src/Breadcrumb/Breadcrumb.Story.svelte
Normal file
|
@ -0,0 +1,36 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
export let noTrailingSlash = undefined;
|
||||
|
||||
import Breadcrumb from "./Breadcrumb.svelte";
|
||||
import BreadcrumbItem from "./BreadcrumbItem.svelte";
|
||||
import BreadcrumbSkeleton from "./Breadcrumb.Skeleton.svelte";
|
||||
</script>
|
||||
|
||||
{#if story === 'current page'}
|
||||
<Breadcrumb noTrailingSlash aria-label="Breadcrumb header">
|
||||
<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}
|
26
src/Breadcrumb/Breadcrumb.stories.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
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" },
|
||||
});
|
17
src/Breadcrumb/Breadcrumb.svelte
Normal file
|
@ -0,0 +1,17 @@
|
|||
<script>
|
||||
export let noTrailingSlash = false;
|
||||
</script>
|
||||
|
||||
<nav
|
||||
aria-label="Breadcrumb"
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave>
|
||||
<ol
|
||||
class:bx--breadcrumb={true}
|
||||
class:bx--breadcrumb--no-trailing-slash={noTrailingSlash}>
|
||||
<slot />
|
||||
</ol>
|
||||
</nav>
|
24
src/Breadcrumb/BreadcrumbItem.svelte
Normal file
|
@ -0,0 +1,24 @@
|
|||
<script>
|
||||
export let href = undefined;
|
||||
export let isCurrentPage = false;
|
||||
|
||||
import { Link } from "../Link";
|
||||
</script>
|
||||
|
||||
<li
|
||||
class:bx--breadcrumb-item={true}
|
||||
class:bx--breadcrumb-item--current={isCurrentPage && $$restProps['aria-current'] !== 'page'}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave>
|
||||
{#if href}
|
||||
<Link {href} aria-current={$$restProps['aria-current']}>
|
||||
<slot />
|
||||
</Link>
|
||||
{:else}
|
||||
<slot
|
||||
props={{ 'aria-current': $$restProps['aria-current'], class: 'bx--link' }} />
|
||||
{/if}
|
||||
</li>
|
3
src/Breadcrumb/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
export { default as Breadcrumb } from "./Breadcrumb.svelte";
|
||||
export { default as BreadcrumbItem } from "./BreadcrumbItem.svelte";
|
||||
export { default as BreadcrumbSkeleton } from "./Breadcrumb.Skeleton.svelte";
|
30
src/Button/Button.Skeleton.svelte
Normal file
|
@ -0,0 +1,30 @@
|
|||
<script>
|
||||
export let href = undefined;
|
||||
export let small = false;
|
||||
</script>
|
||||
|
||||
{#if href}
|
||||
<a
|
||||
{href}
|
||||
role="button"
|
||||
class:bx--skeleton={true}
|
||||
class:bx--btn={true}
|
||||
class:bx--btn--sm={small}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave>
|
||||
{''}
|
||||
</a>
|
||||
{:else}
|
||||
<div
|
||||
class:bx--skeleton={true}
|
||||
class:bx--btn={true}
|
||||
class:bx--btn--sm={small}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave />
|
||||
{/if}
|
70
src/Button/Button.Story.svelte
Normal file
|
@ -0,0 +1,70 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
|
||||
import Button from "./Button.svelte";
|
||||
import ButtonSkeleton from "./Button.Skeleton.svelte";
|
||||
import Add16 from "carbon-icons-svelte/lib/Add16";
|
||||
|
||||
const {
|
||||
kind,
|
||||
disabled,
|
||||
size,
|
||||
iconDescription,
|
||||
small,
|
||||
tooltipPosition,
|
||||
tooltipAlignment
|
||||
} = $$props;
|
||||
|
||||
const regularProps = {
|
||||
kind,
|
||||
disabled,
|
||||
size,
|
||||
iconDescription,
|
||||
small
|
||||
};
|
||||
|
||||
const iconOnlyProps = {
|
||||
hasIconOnly: true,
|
||||
kind,
|
||||
disabled,
|
||||
size,
|
||||
icon: Add16,
|
||||
iconDescription,
|
||||
tooltipPosition,
|
||||
tooltipAlignment
|
||||
};
|
||||
|
||||
const setProps = { disabled, small, size, iconDescription };
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if story === 'skeleton'}
|
||||
<ButtonSkeleton />
|
||||
|
||||
<ButtonSkeleton href="#" />
|
||||
|
||||
<ButtonSkeleton small />
|
||||
{:else if story === 'inline'}
|
||||
<Button />
|
||||
{:else if story === 'icon-only buttons'}
|
||||
<Button {...iconOnlyProps} />
|
||||
{:else if story === 'set of buttons'}
|
||||
<div class="bx--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>
|
||||
<!-- svelte-ignore a11y-missing-attribute -->
|
||||
<a {...props}>Custom component</a>
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
62
src/Button/Button.stories.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
import { withKnobs, select, boolean, text } from "@storybook/addon-knobs";
|
||||
import Component from "./Button.Story.svelte";
|
||||
|
||||
export default { title: "Button", decorators: [withKnobs] };
|
||||
|
||||
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" } });
|
93
src/Button/Button.svelte
Normal file
|
@ -0,0 +1,93 @@
|
|||
<script>
|
||||
export let as = undefined;
|
||||
export let disabled = false;
|
||||
export let href = undefined;
|
||||
export let icon = undefined;
|
||||
export let iconDescription = undefined;
|
||||
export let hasIconOnly = false;
|
||||
export let kind = "primary";
|
||||
export let size = "default";
|
||||
export let tabindex = "0";
|
||||
export let tooltipAlignment = undefined;
|
||||
export let tooltipPosition = undefined;
|
||||
export let type = "button";
|
||||
export let ref = null;
|
||||
|
||||
import { getContext } from "svelte";
|
||||
|
||||
const ctx = getContext("ComposedModal");
|
||||
|
||||
$: if (ctx && ref) {
|
||||
ctx.declareRef(ref);
|
||||
}
|
||||
$: buttonProps = {
|
||||
role: "button",
|
||||
type: href && !disabled ? undefined : type,
|
||||
tabindex,
|
||||
disabled,
|
||||
href,
|
||||
...$$restProps,
|
||||
class: [
|
||||
"bx--btn",
|
||||
size === "field" && "bx--btn--field",
|
||||
size === "small" && "bx--btn--sm",
|
||||
kind && `bx--btn--${kind}`,
|
||||
disabled && "bx--btn--disabled",
|
||||
hasIconOnly && "bx--btn--icon-only",
|
||||
hasIconOnly && "bx--tooltip__trigger",
|
||||
hasIconOnly && "bx--tooltip--a11y",
|
||||
hasIconOnly && tooltipPosition && `bx--tooltip--${tooltipPosition}`,
|
||||
hasIconOnly &&
|
||||
tooltipAlignment &&
|
||||
`bx--tooltip--align-${tooltipAlignment}`,
|
||||
$$restProps.class
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if as}
|
||||
<slot props={buttonProps} />
|
||||
{:else if href && !disabled}
|
||||
<!-- svelte-ignore a11y-missing-attribute -->
|
||||
<a
|
||||
bind:this={ref}
|
||||
{...buttonProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave>
|
||||
{#if hasIconOnly}
|
||||
<span class:bx--assistive-text={true}>{iconDescription}</span>
|
||||
{/if}
|
||||
<slot />
|
||||
{#if icon}
|
||||
<svelte:component
|
||||
this={icon}
|
||||
aria-hidden="true"
|
||||
class="bx--btn__icon"
|
||||
aria-label={iconDescription} />
|
||||
{/if}
|
||||
</a>
|
||||
{:else}
|
||||
<button
|
||||
bind:this={ref}
|
||||
{...buttonProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave>
|
||||
{#if hasIconOnly}
|
||||
<span class:bx--assistive-text={true}>{iconDescription}</span>
|
||||
{/if}
|
||||
<slot />
|
||||
{#if icon}
|
||||
<svelte:component
|
||||
this={icon}
|
||||
aria-hidden="true"
|
||||
class="bx--btn__icon"
|
||||
aria-label={iconDescription} />
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
2
src/Button/index.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
export { default as Button } from "./Button.svelte";
|
||||
export { default as ButtonSkeleton } from "./Button.Skeleton.svelte";
|
11
src/Checkbox/Checkbox.Skeleton.svelte
Normal file
|
@ -0,0 +1,11 @@
|
|||
<div
|
||||
class:bx--form-item={true}
|
||||
class:bx--checkbox-wrapper={true}
|
||||
class:bx--checkbox-label={true}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave>
|
||||
<span class:bx--checkbox-label-text={true} class:bx--skeleton={true} />
|
||||
</div>
|