├── .eslintignore ├── .eslintrc.cjs ├── .github └── workflows │ └── publish.yaml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── cli.cjs ├── package.json ├── packages ├── core │ ├── .gitignore │ ├── .npmrc │ ├── .prettierignore │ ├── .prettierrc │ ├── .storybook │ │ ├── global.css │ │ ├── main.ts │ │ ├── manager.ts │ │ ├── preview-head.html │ │ └── preview.ts │ ├── README.md │ ├── eslint.config.js │ ├── package.json │ ├── playwright.config.ts │ ├── postcss.config.js │ ├── src │ │ ├── app.d.ts │ │ ├── app.html │ │ ├── index.test.ts │ │ ├── lib │ │ │ ├── accordion │ │ │ │ ├── accordion-header.svelte │ │ │ │ ├── accordion-item.svelte │ │ │ │ ├── accordion-panel.svelte │ │ │ │ ├── accordion-root.svelte │ │ │ │ ├── accordion.stories.svelte │ │ │ │ ├── context.ts │ │ │ │ └── index.ts │ │ │ ├── actions │ │ │ │ ├── animation.ts │ │ │ │ ├── dom.ts │ │ │ │ ├── popover.ts │ │ │ │ └── portal.ts │ │ │ ├── app │ │ │ │ ├── backdrop-context.ts │ │ │ │ ├── index.ts │ │ │ │ ├── root-backdrop-layer.svelte │ │ │ │ ├── root-context.ts │ │ │ │ ├── root.svelte │ │ │ │ └── utils.ts │ │ │ ├── avatar │ │ │ │ ├── avatar.stories.svelte │ │ │ │ ├── avatar.svelte │ │ │ │ └── index.ts │ │ │ ├── button │ │ │ │ ├── button.stories.svelte │ │ │ │ ├── button.svelte │ │ │ │ ├── compound-button │ │ │ │ │ ├── compound-button-body.svelte │ │ │ │ │ ├── compound-button-root.svelte │ │ │ │ │ ├── compound-button-secondary-content.svelte │ │ │ │ │ ├── compound-button.stories.svelte │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── menu-button │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── menu-button-button.svelte │ │ │ │ │ ├── menu-button-item.svelte │ │ │ │ │ ├── menu-button-menu.svelte │ │ │ │ │ ├── menu-button-root.svelte │ │ │ │ │ └── menu-button.stories.svelte │ │ │ │ └── types.ts │ │ │ ├── card │ │ │ │ ├── card-appearance.stories.svelte │ │ │ │ ├── card-footer.svelte │ │ │ │ ├── card-header.stories.svelte │ │ │ │ ├── card-header.svelte │ │ │ │ ├── card-preview.svelte │ │ │ │ ├── card-root.svelte │ │ │ │ ├── card-size.stories.svelte │ │ │ │ ├── card.stories.svelte │ │ │ │ ├── context.ts │ │ │ │ └── index.ts │ │ │ ├── checkbox │ │ │ │ ├── checkbox.stories.svelte │ │ │ │ ├── checkbox.svelte │ │ │ │ └── index.ts │ │ │ ├── combobox │ │ │ │ ├── combobox-menu.svelte │ │ │ │ ├── combobox-option.svelte │ │ │ │ ├── combobox-root.svelte │ │ │ │ ├── combobox-trigger.svelte │ │ │ │ ├── combobox.stories.svelte │ │ │ │ ├── context.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── context │ │ │ │ ├── index.ts │ │ │ │ └── sharedContext.ts │ │ │ ├── dialog │ │ │ │ ├── dialog-actions.svelte │ │ │ │ ├── dialog-body.svelte │ │ │ │ ├── dialog-header.svelte │ │ │ │ ├── dialog-root.svelte │ │ │ │ ├── dialog.stories.svelte │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── divider │ │ │ │ ├── divider.stories.svelte │ │ │ │ ├── divider.svelte │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── dropdown │ │ │ │ ├── context.ts │ │ │ │ ├── dropdown-arrow.svelte │ │ │ │ ├── dropdown-item.svelte │ │ │ │ ├── dropdown-menu.svelte │ │ │ │ ├── dropdown-root.svelte │ │ │ │ ├── dropdown-trigger.svelte │ │ │ │ ├── dropdown.stories.svelte │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── field │ │ │ │ ├── context.ts │ │ │ │ ├── field-message-error.svelte │ │ │ │ ├── field-message-info.svelte │ │ │ │ ├── field-message-success.svelte │ │ │ │ ├── field-message-warning.svelte │ │ │ │ ├── field-message.svelte │ │ │ │ ├── field.stories.svelte │ │ │ │ ├── field.svelte │ │ │ │ ├── index.ts │ │ │ │ └── types,.ts │ │ │ ├── icon │ │ │ │ ├── icon.stories.svelte │ │ │ │ ├── icon.svelte │ │ │ │ └── index.ts │ │ │ ├── icons │ │ │ │ ├── add-regular.svelte │ │ │ │ ├── alert-regular.svelte │ │ │ │ ├── arrow-up-regular.svelte │ │ │ │ ├── checkmark-circle-filled.svelte │ │ │ │ ├── checkmark-filled.svelte │ │ │ │ ├── chevron-down-regular.svelte │ │ │ │ ├── chevron-right.svelte │ │ │ │ ├── error-circle-filled.svelte │ │ │ │ ├── info-filled.svelte │ │ │ │ ├── person-regular.svelte │ │ │ │ └── warning-filled.svelte │ │ │ ├── index.ts │ │ │ ├── input │ │ │ │ ├── context.ts │ │ │ │ ├── index.ts │ │ │ │ ├── input-element.svelte │ │ │ │ ├── input-root.svelte │ │ │ │ ├── input.stories.svelte │ │ │ │ ├── input.svelte │ │ │ │ └── types.ts │ │ │ ├── internal │ │ │ │ ├── context.ts │ │ │ │ ├── index.ts │ │ │ │ ├── transition.ts │ │ │ │ └── utils.ts │ │ │ ├── label │ │ │ │ ├── index.ts │ │ │ │ ├── label.stories.svelte │ │ │ │ ├── label.svelte │ │ │ │ └── types.ts │ │ │ ├── layout │ │ │ │ ├── context.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layout.stories.svelte │ │ │ │ └── layout.svelte │ │ │ ├── link │ │ │ │ ├── Link.svelte │ │ │ │ ├── index.ts │ │ │ │ └── link.stories.svelte │ │ │ ├── menu │ │ │ │ ├── context-item.ts │ │ │ │ ├── context-root.ts │ │ │ │ ├── index.ts │ │ │ │ ├── menu-divider.svelte │ │ │ │ ├── menu-group.svelte │ │ │ │ ├── menu-item.svelte │ │ │ │ ├── menu-root.svelte │ │ │ │ ├── menu-trigger.svelte │ │ │ │ ├── menu.stories.svelte │ │ │ │ └── types.ts │ │ │ ├── popover │ │ │ │ ├── context.ts │ │ │ │ ├── index.ts │ │ │ │ ├── popover.stories.svelte │ │ │ │ ├── popover.svelte │ │ │ │ └── types.ts │ │ │ ├── radio │ │ │ │ ├── context.ts │ │ │ │ ├── index.ts │ │ │ │ ├── radio-group.stories.svelte │ │ │ │ ├── radio-group.svelte │ │ │ │ ├── radio.stories.svelte │ │ │ │ ├── radio.svelte │ │ │ │ └── types.ts │ │ │ ├── slider │ │ │ │ ├── index.ts │ │ │ │ ├── slider.stories.svelte │ │ │ │ └── slider.svelte │ │ │ ├── spinner │ │ │ │ ├── index.ts │ │ │ │ ├── spinner-default-icon.svelte │ │ │ │ ├── spinner.stories.svelte │ │ │ │ └── spinner.svelte │ │ │ ├── styles │ │ │ │ └── root.css │ │ │ ├── switch │ │ │ │ ├── index.ts │ │ │ │ ├── switch.stories.svelte │ │ │ │ └── switch.svelte │ │ │ ├── table │ │ │ │ ├── context.ts │ │ │ │ ├── index.ts │ │ │ │ ├── store.ts │ │ │ │ ├── table-root.svelte │ │ │ │ ├── table.stories.svelte │ │ │ │ ├── td-selection.svelte │ │ │ │ ├── td.svelte │ │ │ │ ├── th.svelte │ │ │ │ ├── tr │ │ │ │ │ ├── context.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── tr.svelte │ │ │ │ └── type.ts │ │ │ ├── tailwindcss │ │ │ │ ├── colors_shared.js │ │ │ │ ├── colors_theme.js │ │ │ │ ├── index.ts │ │ │ │ ├── tailwind.config.ts │ │ │ │ ├── typography.js │ │ │ │ └── utils │ │ │ │ │ └── index.ts │ │ │ ├── text │ │ │ │ ├── index.ts │ │ │ │ ├── text.stories.svelte │ │ │ │ └── text.svelte │ │ │ ├── tokens │ │ │ │ └── index.ts │ │ │ ├── tooltip │ │ │ │ ├── index.ts │ │ │ │ ├── tooltip.stories.svelte │ │ │ │ └── tooltip.svelte │ │ │ └── utils │ │ │ │ ├── context.ts │ │ │ │ └── index.ts │ │ ├── mdx │ │ │ └── Introduction.mdx │ │ └── routes │ │ │ └── +page.svelte │ ├── static │ │ └── favicon.png │ ├── svelte.config.js │ ├── tailwind.config.js │ ├── tests │ │ └── test.ts │ ├── tsconfig.json │ ├── tsconfig.tsbuildinfo │ └── vite.config.ts ├── tailwindcss │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── colors_shared.ts │ │ ├── colors_theme.ts │ │ ├── config.ts │ │ ├── index.ts │ │ ├── typography.ts │ │ └── utils │ │ │ └── index.ts │ ├── tsconfig.json │ └── vite.config.ts ├── theme │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── alias │ │ │ ├── darkColor.ts │ │ │ ├── darkColorPalette.ts │ │ │ ├── index.ts │ │ │ ├── lightColor.ts │ │ │ └── lightColorPalette.ts │ │ ├── global │ │ │ ├── brandColors.ts │ │ │ ├── colorPalette.ts │ │ │ ├── colors.ts │ │ │ ├── curves.ts │ │ │ ├── duration.ts │ │ │ ├── fonts.ts │ │ │ ├── index.ts │ │ │ ├── shadow.ts │ │ │ ├── spacings.ts │ │ │ ├── strokeWidth.ts │ │ │ └── timingFunctions.ts │ │ ├── index.ts │ │ ├── sharedColorNames.ts │ │ ├── types.ts │ │ └── utils │ │ │ ├── createDarkTheme.ts │ │ │ ├── createLightTheme.ts │ │ │ ├── index.ts │ │ │ └── shadows.ts │ ├── svelte.config.js │ ├── tsconfig.json │ └── vite.config.ts └── themes │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package.json │ ├── src │ ├── index.ts │ └── web │ │ ├── dark.ts │ │ ├── index.ts │ │ └── light.ts │ ├── svelte.config.js │ ├── tsconfig.json │ └── vite.config.ts ├── playwright.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier', 'plugin:storybook/recommended', "plugin:svelte/recommended"], 5 | plugins: ['@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ 8 | files: ["*.svelte"], 9 | parser: "svelte-eslint-parser", 10 | parserOptions: { 11 | parser: "@typescript-eslint/parser", 12 | }, 13 | }], 14 | settings: { 15 | 'svelte3/typescript': () => require('typescript') 16 | }, 17 | parserOptions: { 18 | sourceType: 'module', 19 | ecmaVersion: 2020 20 | }, 21 | env: { 22 | browser: true, 23 | es2017: true, 24 | node: true 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/209b44b3143be8c8d8a6a6a8f112e7423318e396/.github/workflows/publish.yaml -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /dist 5 | /.svelte-kit 6 | /package 7 | .env 8 | .env.* 9 | !.env.example 10 | vite.config.js.timestamp-* 11 | vite.config.ts.timestamp-* 12 | /storybook-static 13 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | node-linker=hoisted 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 144, 6 | "tabWidth": 1, 7 | "plugins": [ 8 | "prettier-plugin-svelte", 9 | "@trivago/prettier-plugin-sort-imports", 10 | "prettier-plugin-tailwindcss" 11 | ], 12 | "pluginSearchDirs": false, 13 | "overrides": [ 14 | { 15 | "files": "*.svelte", 16 | "options": { 17 | "parser": "svelte" 18 | } 19 | } 20 | ], 21 | "order": "smacss", 22 | "importOrder": [ 23 | "^svelte$", 24 | "^svelte\/.+$", 25 | "^@svelte-fui$", 26 | "^@svelte-fui\/.+$", 27 | "", 28 | "^[$](.*)\/{0, 1}", 29 | "^[$](.*)\/.+", 30 | "^[.]\/{0, 1}", 31 | "^[.]\/.+", 32 | "^[.]{2}\/.+" 33 | ], 34 | "importOrderSeparation": false, 35 | "importOrderSortSpecifiers": true, 36 | "importOrderGroupNamespaceSpecifiers": false 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Abdelhalim Riache 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cli.cjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/209b44b3143be8c8d8a6a6a8f112e7423318e396/cli.cjs -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@svelte-fui/monorepo", 3 | "version": "0.0.1", 4 | "type": "module", 5 | "sideEffects": false, 6 | "scripts": { 7 | "build:core": "cd packages/core && pnpm run build", 8 | "build:storybook": "pnpm run build:theme && pnpm run build:themes && pnpm run build:tailwindcss && cd packages/core && pnpm run storybook:build", 9 | "build:tailwindcss": "cd packages/tailwindcss && pnpm run build", 10 | "build:theme": "cd packages/theme && pnpm run build", 11 | "build:themes": "cd packages/themes && pnpm run build" 12 | }, 13 | "workspaces": [ 14 | "apps/**", 15 | "app/**", 16 | "packages/**" 17 | ], 18 | "devDependencies": { 19 | "@playwright/test": "^1.32.3", 20 | "@sveltejs/kit": "^1.15.7", 21 | "@sveltejs/package": "^2.0.2", 22 | "@trivago/prettier-plugin-sort-imports": "^4.2.0", 23 | "@typescript-eslint/eslint-plugin": "^5.59.0", 24 | "@typescript-eslint/parser": "^5.59.0", 25 | "autoprefixer": "^10.4.14", 26 | "eslint": "^8.38.0", 27 | "eslint-config-prettier": "^8.8.0", 28 | "eslint-plugin-storybook": "^0.6.11", 29 | "eslint-plugin-svelte": "^2.27.2", 30 | "eslint-plugin-svelte3": "^4.0.0", 31 | "prettier": "^2.8.7", 32 | "prettier-plugin-css-order": "^1.3.0", 33 | "prettier-plugin-svelte": "^2.10.0", 34 | "prettier-plugin-tailwindcss": "^0.2.7", 35 | "publint": "^0.1.11", 36 | "svelte": "^4.0.0", 37 | "svelte-check": "^3.2.0", 38 | "tslib": "^2.5.0", 39 | "typescript": "^5.0.4" 40 | }, 41 | "engines": { 42 | "pnpm": ">=8.x", 43 | "node": ">=18.x" 44 | }, 45 | "packageManager": "pnpm@8.14.0" 46 | } 47 | -------------------------------------------------------------------------------- /packages/core/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | storybook-static 3 | 4 | # Output 5 | .output 6 | .vercel 7 | /.svelte-kit 8 | /build 9 | /dist 10 | 11 | # OS 12 | .DS_Store 13 | Thumbs.db 14 | 15 | # Env 16 | .env 17 | .env.* 18 | !.env.example 19 | !.env.test 20 | 21 | # Vite 22 | vite.config.js.timestamp-* 23 | vite.config.ts.timestamp-* 24 | 25 | *storybook.log -------------------------------------------------------------------------------- /packages/core/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /packages/core/.prettierignore: -------------------------------------------------------------------------------- 1 | # Package Managers 2 | package-lock.json 3 | pnpm-lock.yaml 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /packages/core/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 8 | } 9 | -------------------------------------------------------------------------------- /packages/core/.storybook/global.css: -------------------------------------------------------------------------------- 1 | html, 2 | body.sb-show-main { 3 | width: 100%; 4 | height: 100%; 5 | margin: 0; 6 | padding: 0 !important; 7 | /* background-color: whitesmoke !important; */ 8 | } 9 | 10 | #storybook-root { 11 | width: 100%; 12 | height: 100%; 13 | padding: 0; 14 | } 15 | 16 | #storybook-root[hidden=true] { 17 | display: none; 18 | } 19 | -------------------------------------------------------------------------------- /packages/core/.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from '@storybook/sveltekit'; 2 | import { mergeConfig, searchForWorkspaceRoot } from 'vite'; 3 | 4 | import { join, dirname, resolve } from 'path'; 5 | 6 | /** 7 | * This function is used to resolve the absolute path of a package. 8 | * It is needed in projects that use Yarn PnP or are set up within a monorepo. 9 | */ 10 | function getAbsolutePath(value: string): any { 11 | return dirname(require.resolve(join(value, 'package.json'))); 12 | } 13 | const config: StorybookConfig = { 14 | stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx|svelte)'], 15 | addons: [ 16 | '@storybook/addon-svelte-csf', 17 | '@storybook/addon-links', 18 | '@storybook/addon-essentials', 19 | '@chromatic-com/storybook', 20 | '@storybook/addon-interactions', 21 | ], 22 | framework: { 23 | name: '@storybook/sveltekit', 24 | options: {} 25 | }, 26 | viteFinal(config) { 27 | const cwd = searchForWorkspaceRoot(process.cwd()); 28 | 29 | const docgenPlugin = ((config.plugins ?? []) as Plugin[]).find( 30 | (plugin) => plugin.name === 'storybook:svelte-docgen-plugin' 31 | ); 32 | if (docgenPlugin) { 33 | const origTransform = docgenPlugin.transform; 34 | const newTransform: typeof origTransform = (code, id, options) => { 35 | // ignore unplugin-icons resources 36 | if (id.startsWith('~icons/')) { 37 | return; 38 | } 39 | return (origTransform as Function)?.call(docgenPlugin, code, id, options); 40 | }; 41 | docgenPlugin.transform = newTransform; 42 | docgenPlugin.enforce = 'post'; 43 | } 44 | 45 | const currentFsAllow = config?.server?.fs?.allow ?? []; 46 | const _ = mergeConfig(config, { 47 | server: { 48 | fs: { 49 | allow: [ 50 | ...currentFsAllow, 51 | resolve(cwd, 'src/lib'), 52 | resolve(cwd, 'src/routes'), 53 | resolve(cwd, '.svelte-kit'), 54 | resolve(cwd, 'src'), 55 | resolve(cwd, '.node_modules'), 56 | resolve(cwd, '.storybook'), 57 | resolve(cwd, 'tailwind.config.js') 58 | ] 59 | } 60 | } 61 | }); 62 | 63 | return _; 64 | } 65 | }; 66 | export default config; 67 | -------------------------------------------------------------------------------- /packages/core/.storybook/manager.ts: -------------------------------------------------------------------------------- 1 | import { addons } from '@storybook/manager-api'; 2 | // import { themes } from '@storybook/theming'; 3 | 4 | addons.setConfig({ 5 | panelPosition: 'right', 6 | }); 7 | -------------------------------------------------------------------------------- /packages/core/.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import type { Preview } from '@storybook/svelte'; 2 | import './global.css'; 3 | import '../src/lib/styles/root.css'; 4 | 5 | const preview: Preview = { 6 | parameters: { 7 | backgrounds: { 8 | default: 'light' 9 | }, 10 | controls: { 11 | matchers: { 12 | color: /(background|color)$/i, 13 | date: /Date$/ 14 | } 15 | } 16 | }, 17 | 18 | tags: ['autodocs'] 19 | }; 20 | 21 | export default preview; -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # @svelte-fui/core 2 | 3 | Contains all the necessary UI component of the Fluent Design System (Still under development) 4 | 5 | # Usage 6 | 7 | Add @fluentui/react-components to a project: 8 | 9 | ```shell 10 | // pnpm 11 | pnpm install @svelte-fui/core 12 | 13 | //npm 14 | npm install @svelte-fui/core 15 | ``` 16 | 17 | To use Fluent design for Sveltekit app you have to make `App` component at the top level route, ex: `/routes/+layout.svelte` 18 | 19 | ```html 20 | 29 | 30 | 31 | 32 | 33 | ``` 34 | 35 | # Using FUI preset fot TailwindCSS 36 | 37 | This will allow you to integrate FUI tokens into your TailwindCSS config. 38 | 39 | 40 | ```bash 41 | // pnpm 42 | pnpm install @svelte-fui/tailwindcss 43 | 44 | //npm 45 | npm install @svelte-fui/tailwindcss 46 | ``` 47 | 48 | ```js 49 | // tailwindcss.config.js 50 | 51 | import { fuiPreset } from '@svelte-fui/tailwindcss'; 52 | 53 | /** @type {import('tailwindcss').Config} */ 54 | export default { 55 | presets: [fuiPreset], 56 | content: ['./src/**/*.{html,js,svelte, stories.svelte, ts}'] 57 | }; 58 | ``` 59 | 60 | Now in your `.svelte` file you can use FUI tokens as tw classes: 61 | 62 | ```html 63 | 64 | 67 | 68 | 69 | 70 |
71 | 72 |
73 | ``` 74 | # Use Pre-Defined Themes 75 | 76 | ```bash 77 | // pnpm 78 | pnpm install @svelte-fui/themes 79 | 80 | //npm 81 | npm install @svelte-fui/themes 82 | ``` 83 | ```html 84 | 106 | 107 | 108 | 109 | 110 | ``` 111 | -------------------------------------------------------------------------------- /packages/core/eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import ts from 'typescript-eslint'; 3 | import svelte from 'eslint-plugin-svelte'; 4 | import prettier from 'eslint-config-prettier'; 5 | import globals from 'globals'; 6 | 7 | /** @type {import('eslint').Linter.FlatConfig[]} */ 8 | export default [ 9 | js.configs.recommended, 10 | ...ts.configs.recommended, 11 | ...svelte.configs['flat/recommended'], 12 | prettier, 13 | ...svelte.configs['flat/prettier'], 14 | { 15 | languageOptions: { 16 | globals: { 17 | ...globals.browser, 18 | ...globals.node 19 | } 20 | } 21 | }, 22 | { 23 | files: ['**/*.svelte'], 24 | languageOptions: { 25 | parserOptions: { 26 | parser: ts.parser 27 | } 28 | } 29 | }, 30 | { 31 | ignores: ['build/', '.svelte-kit/', 'dist/'] 32 | } 33 | ]; 34 | -------------------------------------------------------------------------------- /packages/core/playwright.config.ts: -------------------------------------------------------------------------------- 1 | import type { PlaywrightTestConfig } from '@playwright/test'; 2 | 3 | const config: PlaywrightTestConfig = { 4 | webServer: { 5 | command: 'npm run build && npm run preview', 6 | port: 4173 7 | }, 8 | testDir: 'tests', 9 | testMatch: /(.+\.)?(test|spec)\.[jt]s/ 10 | }; 11 | 12 | export default config; 13 | -------------------------------------------------------------------------------- /packages/core/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | 'tailwindcss/nesting': {}, 4 | tailwindcss: {}, 5 | 'postcss-preset-env': { 6 | features: { 'nesting-rules': false }, 7 | }, 8 | autoprefixer: {}, 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /packages/core/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface PageState {} 9 | // interface Platform {} 10 | } 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /packages/core/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/core/src/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | describe('sum test', () => { 4 | it('adds 1 + 2 to equal 3', () => { 5 | expect(1 + 2).toBe(3); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/core/src/lib/accordion/accordion-item.svelte: -------------------------------------------------------------------------------- 1 | 84 | 85 |
86 | 87 |
88 | 89 | 93 | -------------------------------------------------------------------------------- /packages/core/src/lib/accordion/accordion-panel.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | {#if $active$} 13 | 14 |
15 | 16 |
17 | {/if} 18 | 19 | 24 | -------------------------------------------------------------------------------- /packages/core/src/lib/accordion/accordion-root.svelte: -------------------------------------------------------------------------------- 1 | 33 | 34 |
35 | 36 |
37 | 38 | 40 | -------------------------------------------------------------------------------- /packages/core/src/lib/accordion/context.ts: -------------------------------------------------------------------------------- 1 | import { buildContext } from '@svelte-fui/core/utils/context'; 2 | import { getContext, setContext } from 'svelte'; 3 | import { type Readable, type Writable, writable } from 'svelte/store'; 4 | 5 | const ACCORDION_CONTEXT_KEY = 'fui_accordion_context_key'; 6 | 7 | type AccordionItem = { 8 | value: string; 9 | data: unknown | undefined; 10 | selected?: boolean; 11 | }; 12 | 13 | export type AccordionContext = { 14 | selectedValue$: Writable; 15 | selectedData$: Writable; 16 | collapsible$: Readable; 17 | multiple$: Readable; 18 | items$: Writable>; 19 | }; 20 | 21 | const builders: Record any> = { 22 | selectedValue$: () => writable(''), 23 | selectedData$: () => writable(), 24 | collapsible$: () => writable(false), 25 | multiple$: () => writable(false), 26 | items$: () => writable({}) 27 | }; 28 | 29 | export function getAccordionContext() { 30 | return getContext(ACCORDION_CONTEXT_KEY) as AccordionContext; 31 | } 32 | 33 | export function setAccordionContext(context: Partial = {}): AccordionContext { 34 | return setContext(ACCORDION_CONTEXT_KEY, buildContext(context, builders)); 35 | } 36 | 37 | export const ACCORDIO_ITEM_CONTEXT_KEY = 'fui_accordion_item_context_key'; 38 | 39 | export type AccordionItemContext = { 40 | active$: Readable; 41 | }; 42 | 43 | const accordionItemBuilders: Record any> = { 44 | active$: () => writable(false) 45 | }; 46 | 47 | export function getAccordionItemContext() { 48 | return getContext(ACCORDIO_ITEM_CONTEXT_KEY) as AccordionItemContext; 49 | } 50 | 51 | export function setAccordionItemContext(context: Partial = {}): AccordionItemContext { 52 | return setContext(ACCORDIO_ITEM_CONTEXT_KEY, buildContext(context, accordionItemBuilders)); 53 | } 54 | -------------------------------------------------------------------------------- /packages/core/src/lib/accordion/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Accordion } from './accordion-root.svelte'; 2 | export { default as AccordionHeader } from './accordion-header.svelte'; 3 | export { default as AccordionItem } from './accordion-item.svelte'; 4 | export { default as AccordionPanel } from './accordion-panel.svelte'; 5 | -------------------------------------------------------------------------------- /packages/core/src/lib/actions/animation.ts: -------------------------------------------------------------------------------- 1 | import { gsap } from 'gsap'; 2 | 3 | export function animate(node: HTMLElement | SVGElement, vars: gsap.TweenVars) { 4 | gsap.set(node, vars); 5 | 6 | return { 7 | update(vars: gsap.TweenVars) { 8 | gsap.to(node, vars); 9 | } 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/actions/dom.ts: -------------------------------------------------------------------------------- 1 | import { tick } from 'svelte'; 2 | import type { DragEventHandler } from 'svelte/elements'; 3 | 4 | export type ClickOUtsideParams = { 5 | exclude: (string | Element)[]; 6 | callback: (ev?: MouseEvent) => void; 7 | }; 8 | 9 | export function clickOutside(node: Element, { callback, exclude = [] }: ClickOUtsideParams) { 10 | document.addEventListener('click', handler); 11 | 12 | return { 13 | destroy() { 14 | document.removeEventListener('click', handler); 15 | } 16 | }; 17 | 18 | function handler(ev: MouseEvent) { 19 | const target = ev.target as HTMLElement | undefined; 20 | if (target && !node.contains(target)) { 21 | // user clicked outside the current element 22 | 23 | // Check wethere the target is excluded or not 24 | const excludedElements = exclude 25 | .filter(Boolean) 26 | .map((d) => { 27 | if (d instanceof Element) return d; 28 | 29 | return [...document.querySelectorAll(`[data-${d}]`).values()]; 30 | }) 31 | .flat(); 32 | 33 | if (excludedElements.some((d) => d.contains(target))) { 34 | // Do not fire click outside, target element excluded 35 | return; 36 | } 37 | 38 | callback(ev); 39 | return; 40 | } 41 | } 42 | } 43 | 44 | export type DropzoneParams = { 45 | onDragEnter?: DragEventHandler; 46 | onDragLeave?: DragEventHandler; 47 | onDragOver?: DragEventHandler; 48 | onDrop?: DragEventHandler; 49 | }; 50 | export function dropzone(node: HTMLElement, { onDrop, onDragEnter, onDragLeave, onDragOver }: DropzoneParams) { 51 | const on_drag_enter = (ev: DragEvent) => { 52 | ev.preventDefault(); 53 | onDragEnter?.(ev); 54 | }; 55 | const on_drag_over = (ev: DragEvent) => { 56 | ev.preventDefault(); 57 | onDragOver?.(ev); 58 | }; 59 | const on_drag_leave = (ev: DragEvent) => { 60 | onDragLeave?.(ev); 61 | }; 62 | const on_drop = (ev: DragEvent) => { 63 | ev.preventDefault(); 64 | onDrop?.(ev); 65 | }; 66 | 67 | node.addEventListener('dragenter', on_drag_enter); 68 | node.addEventListener('dragleave', on_drag_leave); 69 | node.addEventListener('dragover', on_drag_over); 70 | node.addEventListener('drop', on_drop); 71 | 72 | return { 73 | destroy() { 74 | node.removeEventListener('dragenter', on_drag_enter); 75 | node.removeEventListener('dragleave', on_drag_leave); 76 | node.removeEventListener('dragover', on_drag_over); 77 | node.removeEventListener('drop', on_drop); 78 | } 79 | }; 80 | } 81 | 82 | export function frame(node: HTMLElement) { 83 | const resize = (node: HTMLElement) => { 84 | const parentElement = node.parentElement; 85 | 86 | if (!parentElement) return; 87 | 88 | parentElement.style.width = `${node.clientWidth}px`; 89 | parentElement.style.height = `${node.clientHeight}px`; 90 | }; 91 | 92 | const observer = new ResizeObserver(() => resize(node)); 93 | observer.observe(node); 94 | 95 | resize(node) 96 | 97 | return { 98 | destroy() { 99 | observer.disconnect; 100 | } 101 | }; 102 | } 103 | -------------------------------------------------------------------------------- /packages/core/src/lib/actions/portal.ts: -------------------------------------------------------------------------------- 1 | import { tick } from 'svelte'; 2 | 3 | export type PortalParams = { 4 | target: HTMLElement; 5 | onMount?: () => void; 6 | onUpdate?: () => void; 7 | }; 8 | export function portal(node: HTMLElement, { target = document.body, onMount = () => {}, onUpdate = () => {} }: PortalParams) { 9 | tick().then(() => { 10 | port(node, target); 11 | onMount(); 12 | }); 13 | 14 | return { 15 | destroy() { 16 | node.remove(); 17 | }, 18 | update(target: HTMLElement = document.body) { 19 | tick().then(() => { 20 | port(node, target); 21 | onUpdate(); 22 | }); 23 | } 24 | }; 25 | } 26 | 27 | function port(node: HTMLElement, target: HTMLElement = document.body) { 28 | if (!target) { 29 | throw Error('[actions] portal: Target element is undefined.'); 30 | } 31 | 32 | if (node.parentElement === target) { 33 | // Element is already mounted on target 34 | return; 35 | } 36 | 37 | node.hidden = true; 38 | 39 | target.appendChild(node); 40 | 41 | node.hidden = false; 42 | } 43 | -------------------------------------------------------------------------------- /packages/core/src/lib/app/backdrop-context.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | import type { Writable } from 'svelte/store'; 3 | 4 | export const FUI_BACKDROP_CONTEXT_KEY = 'fui-context/backdrop'; 5 | 6 | export type BackdropContext = { 7 | dependencies: Set; 8 | open: Writable; 9 | openBackdrop: (id: string) => void; 10 | closeBackdrop: (is: string) => void; 11 | }; 12 | 13 | export function getBackdropContext(): BackdropContext { 14 | return getContext(FUI_BACKDROP_CONTEXT_KEY); 15 | } 16 | 17 | export function setBackdropContext(context: BackdropContext): BackdropContext { 18 | return setContext(FUI_BACKDROP_CONTEXT_KEY, context); 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/lib/app/index.ts: -------------------------------------------------------------------------------- 1 | export { default as App } from './root.svelte'; 2 | export { default as FluentRoot } from './root.svelte'; 3 | export * from './root-context'; 4 | export * from './backdrop-context'; 5 | -------------------------------------------------------------------------------- /packages/core/src/lib/app/root-backdrop-layer.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 |
16 | 17 | -------------------------------------------------------------------------------- /packages/core/src/lib/app/root-context.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | import { type Readable, type Writable } from 'svelte/store'; 3 | 4 | export const FUI_ROOT_CONTEXT_KEY = 'fui-context/root'; 5 | 6 | export type FluentRootContext = { 7 | appElement$: Writable; 8 | 9 | rootElement: Writable; 10 | overlayElement: Writable; 11 | screens: Readable>; 12 | activeScreen: Readable<[key: string, value: string]>; 13 | layouts: Writable< 14 | Record< 15 | string, 16 | { 17 | element: HTMLElement; 18 | id: string; 19 | } 20 | > 21 | >; 22 | }; 23 | 24 | export function getFluentRootContext() { 25 | return getContext(FUI_ROOT_CONTEXT_KEY) as FluentRootContext; 26 | } 27 | 28 | export function setFluentRootContext(context: FluentRootContext): FluentRootContext { 29 | return setContext(FUI_ROOT_CONTEXT_KEY, context); 30 | } 31 | -------------------------------------------------------------------------------- /packages/core/src/lib/app/root.svelte: -------------------------------------------------------------------------------- 1 | 61 | 62 |
63 | {#await tick() then _} 64 | 65 | 66 | {/await} 67 | 68 | 69 | 70 | 71 |
72 | 73 | 93 | -------------------------------------------------------------------------------- /packages/core/src/lib/app/utils.ts: -------------------------------------------------------------------------------- 1 | import type { Theme } from 'svelte-fui/theme'; 2 | 3 | export function applyTheme(element: HTMLElement, styleElement: HTMLStyleElement, theme: Theme) { 4 | const classname = element.classList.item(element.classList.length - 1) 5 | 6 | const vars = Object.entries(theme).reduce((acc, [key, value]) => { 7 | return acc + `--fui-${key}: ${value};`; 8 | }, ''); 9 | 10 | 11 | if(styleElement.sheet.cssRules.length){ 12 | styleElement.sheet.deleteRule(0); 13 | } 14 | 15 | styleElement.sheet.insertRule(`.fui-root.${classname} { ${vars} }`, 0); 16 | } 17 | -------------------------------------------------------------------------------- /packages/core/src/lib/avatar/avatar.stories.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 | 40 | 41 | 42 | 43 |
44 | 45 |
46 |
47 |
48 | -------------------------------------------------------------------------------- /packages/core/src/lib/avatar/index.ts: -------------------------------------------------------------------------------- 1 | export {default as Avatar } from './avatar.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/button.stories.svelte: -------------------------------------------------------------------------------- 1 | 43 | 44 | 63 | 64 | 65 | 66 |
67 |
68 | 69 | 70 | 80 | 81 | 90 |
91 | 92 | 93 |
94 |
95 |
96 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/compound-button/compound-button-body.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/compound-button/compound-button-secondary-content.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 |
5 | 6 |
7 | 8 | 16 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/compound-button/compound-button.stories.svelte: -------------------------------------------------------------------------------- 1 | 39 | 40 | 71 | 72 | 73 | 74 |
75 | 76 | 77 | 78 | 79 | 80 |
Example
81 | Secondary content 82 |
83 |
84 | 85 | 86 | 87 | 88 | 89 | 90 |
91 |
92 |
93 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/compound-button/index.ts: -------------------------------------------------------------------------------- 1 | import { default as CompoundButtonRoot } from './compound-button-root.svelte'; 2 | import { default as CompoundButtonBody } from './compound-button-body.svelte'; 3 | import { default as CompoundButtonSecondaryContent } from './compound-button-secondary-content.svelte'; 4 | 5 | export const CompoundButton = { 6 | Root: CompoundButtonRoot, 7 | Body: CompoundButtonBody, 8 | SecondaryContent: CompoundButtonSecondaryContent 9 | }; 10 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Button } from './button.svelte'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/menu-button/index.ts: -------------------------------------------------------------------------------- 1 | import MenuButtonRoot from "./menu-button-root.svelte"; 2 | import MenuButtonButton from "./menu-button-button.svelte"; 3 | import MenuButtonMenu from "./menu-button-menu.svelte"; 4 | import MenuButtonItem from "./menu-button-item.svelte"; 5 | 6 | export const MenuButton = { 7 | Root: MenuButtonRoot, 8 | Button: MenuButtonButton, 9 | Menu: MenuButtonMenu, 10 | Item: MenuButtonItem 11 | } -------------------------------------------------------------------------------- /packages/core/src/lib/button/menu-button/menu-button-button.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/menu-button/menu-button-item.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/menu-button/menu-button-menu.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/menu-button/menu-button-root.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/menu-button/menu-button.stories.svelte: -------------------------------------------------------------------------------- 1 | 45 | 46 | 65 | 66 | 67 | 68 |
69 |
70 | 71 | 72 | 73 | {#if hover} 74 | 75 | {:else} 76 | 77 | {/if} 78 | 79 |
New
80 |
81 | 82 | 83 | Item 1 84 | Item 2 85 | Item 3 86 | 87 |
88 |
89 |
90 |
91 |
92 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/types.ts: -------------------------------------------------------------------------------- 1 | import type { HTMLAttributes } from 'svelte/elements'; 2 | 3 | export type ButtonShape = 'rounded' | 'circular' | 'square'; 4 | export type ButtonAppearance = 'subtle' | 'outline' | 'secondary' | 'primary' | 'transparent'; 5 | export type ButtonSize = 'sm' | 'md' | 'lg'; 6 | 7 | export type ButtonProps = HTMLAttributes & { 8 | shape?: ButtonShape; 9 | appearance?: ButtonAppearance; 10 | size?: ButtonSize; 11 | 12 | /** @restProps {button | a} */ 13 | /** Specifies the visual styling of the button. */ 14 | // export let variant: 'standard' | 'accent' | 'hyperlink' = 'standard'; 15 | 16 | /** Sets an href value and converts the button element into an anchor/ */ 17 | href?: string; 18 | 19 | /** Controls whether the button is intended for user interaction, and styles it accordingly. */ 20 | disabled?: boolean; 21 | 22 | icon?: boolean; 23 | 24 | /** Obtains a bound DOM reference to the button or anchor element. */ 25 | element?: HTMLElement; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/core/src/lib/card/card-footer.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | 11 |
12 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /packages/core/src/lib/card/card-header.stories.svelte: -------------------------------------------------------------------------------- 1 | 57 | 58 | 77 | 78 | 79 | 80 |
81 | 82 | App name logo 87 | Alert in Teams when a new document is uploaded in channel 88 | By Microsoft 89 | 90 | 91 | 92 | 93 | 94 |
95 |
96 |
97 | -------------------------------------------------------------------------------- /packages/core/src/lib/card/card-header.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | 22 | 23 |
24 | 25 | 66 | -------------------------------------------------------------------------------- /packages/core/src/lib/card/card-preview.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |
13 | 14 | 15 |
16 | 17 | 36 | -------------------------------------------------------------------------------- /packages/core/src/lib/card/context.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | import { type Writable, writable } from 'svelte/store'; 3 | 4 | const key = 'fui_card_context'; 5 | 6 | type OnOptionClickOptions = { 7 | id: string; 8 | value: string; 9 | selected: boolean; 10 | }; 11 | export type CardContext = { 12 | selectedId$: Writable; 13 | selectedValue$: Writable; 14 | onOptionClick: (options: OnOptionClickOptions) => void; 15 | }; 16 | 17 | const builders: Record any> = { 18 | selectedId$: () => writable(''), 19 | selectedValue$: () => writable(''), 20 | onOptionClick: () => () => { 21 | return; 22 | } 23 | }; 24 | 25 | function buildContext(context: Partial = {}) { 26 | const keys: Set = new Set(['selectedId$', 'selectedValue$']); 27 | 28 | Object.keys(context).forEach((key) => keys.delete(key)); 29 | 30 | for (const key of keys) { 31 | context[key] = builders[key](); 32 | } 33 | 34 | return context as CardContext; 35 | } 36 | 37 | export function getCardContext() { 38 | return getContext(key) as CardContext; 39 | } 40 | 41 | export function setCardContext(context: Partial = {}): CardContext { 42 | return setContext(key, buildContext(context)); 43 | } 44 | -------------------------------------------------------------------------------- /packages/core/src/lib/card/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Card } from './card-root.svelte'; 2 | export { default as CardPreview } from './card-preview.svelte'; 3 | export { default as CardHeader } from './card-header.svelte'; 4 | export { default as CardFooter } from './card-footer.svelte'; 5 | -------------------------------------------------------------------------------- /packages/core/src/lib/checkbox/checkbox.stories.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 41 | 42 |
43 | 44 | 48 |
49 |
50 |
51 | -------------------------------------------------------------------------------- /packages/core/src/lib/checkbox/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Checkbox } from './checkbox.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/combobox/combobox-menu.svelte: -------------------------------------------------------------------------------- 1 | 59 | 60 | 61 |
74 | 75 |
76 |
77 | -------------------------------------------------------------------------------- /packages/core/src/lib/combobox/combobox-root.svelte: -------------------------------------------------------------------------------- 1 | 76 | 77 |
{}}> 78 | 88 | 89 |
90 | -------------------------------------------------------------------------------- /packages/core/src/lib/combobox/combobox-trigger.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | {#if !$value_store} 28 |
29 |
{placeholder}
30 |
31 | {:else} 32 | 33 | {$text_store} 34 | 35 | {/if} 36 | 37 | 38 |
39 |
40 | -------------------------------------------------------------------------------- /packages/core/src/lib/combobox/combobox.stories.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | Arabic 48 | English 49 | Spanish 50 | Italian 51 | Frensh 52 | 53 | 54 | 55 | 59 |
60 |
61 |
62 |
63 | -------------------------------------------------------------------------------- /packages/core/src/lib/combobox/context.ts: -------------------------------------------------------------------------------- 1 | import type { DropdownContext } from '@svelte-fui/core/dropdown/context'; 2 | import { getFluentContext, setFluentContext } from '@svelte-fui/core/internal/context'; 3 | 4 | export const comboboxNamespace = 'dropdown'; 5 | 6 | export type ComboboxContext = DropdownContext & {}; 7 | 8 | export function getComboboxContext() { 9 | return getFluentContext(comboboxNamespace) as ComboboxContext; 10 | } 11 | 12 | export function setComboboxContext(context: ComboboxContext): ComboboxContext { 13 | return setFluentContext>(context, comboboxNamespace); 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/src/lib/combobox/index.ts: -------------------------------------------------------------------------------- 1 | import { Dropdown } from '@svelte-fui/core/dropdown'; 2 | import ComboboxRoot from './combobox-root.svelte'; 3 | import ComboboxTrigger from './combobox-trigger.svelte'; 4 | 5 | export const Combobox = { 6 | Root: ComboboxRoot, 7 | Menu: Dropdown.Menu, 8 | Item: Dropdown.Item, 9 | Trigger: ComboboxTrigger, 10 | Arrow: Dropdown.Arrow 11 | }; 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/combobox/types.ts: -------------------------------------------------------------------------------- 1 | export type ComboboxTriggerProps = { 2 | class?: string; 3 | placeholder?: string; 4 | }; 5 | -------------------------------------------------------------------------------- /packages/core/src/lib/context/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sharedContext' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/context/sharedContext.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | import { type Readable, type Writable, writable } from 'svelte/store'; 3 | 4 | export const SVELTE_FUI_SHARED_CONTEXT_KEY = '@fui/context/shared'; 5 | 6 | export type SharedContext = Record & T; 7 | 8 | /** 9 | * 10 | * @deprecated 11 | */ 12 | export function getSharedContext(...segment: string[]): Readable> { 13 | return getContext( 14 | [SVELTE_FUI_SHARED_CONTEXT_KEY, ...segment.filter(Boolean)].join('/') 15 | ) as Writable>; 16 | } 17 | 18 | /** 19 | * 20 | * @deprecated 21 | */ 22 | export function setSharedContext( 23 | context: SharedContext, 24 | ...segments: string[] 25 | ): Writable> { 26 | return setContext( 27 | [SVELTE_FUI_SHARED_CONTEXT_KEY, ...segments.filter(Boolean)].join('/'), 28 | writable(structuredClone(context)) 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /packages/core/src/lib/dialog/dialog-actions.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
14 | 15 |
16 | -------------------------------------------------------------------------------- /packages/core/src/lib/dialog/dialog-body.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 10 |
11 | -------------------------------------------------------------------------------- /packages/core/src/lib/dialog/dialog-header.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/dialog/index.ts: -------------------------------------------------------------------------------- 1 | import { default as DialogActions } from './dialog-actions.svelte'; 2 | import { default as DialogBody } from './dialog-body.svelte'; 3 | import { default as DialogHeader } from './dialog-header.svelte'; 4 | import { default as DialogRoot } from './dialog-root.svelte'; 5 | 6 | export const Dialog = { 7 | Root: DialogRoot, 8 | Actions: DialogActions, 9 | Body: DialogBody, 10 | Header: DialogHeader 11 | }; 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/dialog/types.ts: -------------------------------------------------------------------------------- 1 | import type { HTMLAttributes } from 'svelte/elements'; 2 | 3 | export type DialogType = 'modal' | 'non-modal' | 'alert'; 4 | 5 | export type DialogProps = HTMLAttributes & { 6 | open: boolean; 7 | type: DialogType; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/core/src/lib/divider/divider.stories.svelte: -------------------------------------------------------------------------------- 1 | 37 | 38 | 57 | 58 | 59 | 60 |
61 |
62 |
63 | 64 |
65 | 66 |
67 | Text 68 |
69 |
70 | 71 |
72 |
73 | Text 74 |
75 |
76 |
77 |
78 |
79 | -------------------------------------------------------------------------------- /packages/core/src/lib/divider/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Divider } from './divider.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/divider/types.ts: -------------------------------------------------------------------------------- 1 | import type { HTMLAttributes } from 'svelte/elements'; 2 | 3 | export type DividerAppearance = 'strong' | 'brand' | 'subtl' | 'default'; 4 | export type DividerAlignContent = 'center' | 'start' | 'end'; 5 | 6 | export type DividerProps = HTMLAttributes & { 7 | appearance?: DividerAppearance; 8 | vertical?: boolean; 9 | inset?: boolean; 10 | alignContent?: DividerAlignContent; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/dropdown/context.ts: -------------------------------------------------------------------------------- 1 | import type { Writable } from 'svelte/store'; 2 | import { getFluentContext, setFluentContext } from '../internal/context'; 3 | 4 | export const dropdownNamespace = 'dropdown'; 5 | 6 | type OnChangeProps = { 7 | value: string; 8 | text: string; 9 | data: T; 10 | }; 11 | export type DropdownContext = { 12 | id: Writable; 13 | open: Writable; 14 | value: Writable; 15 | data: Writable; 16 | text: Writable; 17 | triggerElement: Writable; 18 | openMenu: (delay?: number) => void; 19 | closeMenu: (delay?: number) => void; 20 | onChange: (props: OnChangeProps) => void; 21 | }; 22 | 23 | export function getDropdownContext() { 24 | return getFluentContext>(dropdownNamespace); 25 | } 26 | 27 | export function setDropdownContext(context: DropdownContext) { 28 | return setFluentContext(context, dropdownNamespace); 29 | } 30 | -------------------------------------------------------------------------------- /packages/core/src/lib/dropdown/dropdown-arrow.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 |
27 | 28 | 29 | 30 |
31 | -------------------------------------------------------------------------------- /packages/core/src/lib/dropdown/dropdown-item.svelte: -------------------------------------------------------------------------------- 1 | 55 | 56 | 71 | 72 | 86 | -------------------------------------------------------------------------------- /packages/core/src/lib/dropdown/dropdown-root.svelte: -------------------------------------------------------------------------------- 1 | 68 | 69 |
70 | 71 | 72 | 73 |
74 | -------------------------------------------------------------------------------- /packages/core/src/lib/dropdown/dropdown-trigger.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 | 35 | 36 | 38 | -------------------------------------------------------------------------------- /packages/core/src/lib/dropdown/dropdown.stories.svelte: -------------------------------------------------------------------------------- 1 | 46 | 47 | 74 | 75 | 76 | 77 |
78 |
79 | 80 | 81 | 82 | {#if data} 83 | {data.lang} 84 | {:else} 85 | Select a language 86 | {/if} 87 | 88 | 89 | 90 | 91 | 92 | 93 | {#each languages as item (item.id)} 94 | {item.lang} 95 | {/each} 96 | 97 | 98 | 99 |
100 | Selected language: 101 | {language} 102 |
103 |
104 |
105 |
106 |
107 | -------------------------------------------------------------------------------- /packages/core/src/lib/dropdown/index.ts: -------------------------------------------------------------------------------- 1 | import { default as DropdownArrow } from './dropdown-arrow.svelte'; 2 | import { default as DropdownItem } from './dropdown-item.svelte'; 3 | import { default as DropdownMenu } from './dropdown-menu.svelte'; 4 | import { default as DropdownRoot } from './dropdown-root.svelte'; 5 | import { default as DropdownTrigger } from './dropdown-trigger.svelte'; 6 | 7 | export const Dropdown = { 8 | Root: DropdownRoot, 9 | Trigger: DropdownTrigger, 10 | Menu: DropdownMenu, 11 | Item: DropdownItem, 12 | Arrow: DropdownArrow 13 | }; 14 | -------------------------------------------------------------------------------- /packages/core/src/lib/dropdown/types.ts: -------------------------------------------------------------------------------- 1 | import type { Placement } from '@floating-ui/dom'; 2 | import type { HTMLInputAttributes } from 'svelte/elements'; 3 | 4 | export type DropdownProps = HTMLInputAttributes & { 5 | open?: boolean; 6 | value?: string; 7 | data?: T; 8 | class?: string; 9 | id?: string; 10 | discover?: boolean; 11 | offset?: number; 12 | }; 13 | 14 | export type DropdownTriggerProps = { 15 | class?: string; 16 | }; 17 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/context.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | import { type Writable, writable } from 'svelte/store'; 3 | import type { FieldState } from './types,'; 4 | 5 | export const SVELTE_FUI_FIELD_CONTEXT_KEY = 'svelte-fui-field-context-key'; 6 | 7 | export type FieldContext = { 8 | state$: Writable; 9 | icon$: Writable; 10 | }; 11 | 12 | export function getFieldContext(): FieldContext { 13 | return getContext(SVELTE_FUI_FIELD_CONTEXT_KEY); 14 | } 15 | 16 | export function setFieldContext(values: { state: FieldState; icon: any | undefined }) { 17 | const context: FieldContext = { 18 | state$: writable(values.state), 19 | icon$: writable(values.icon) 20 | }; 21 | 22 | return setContext(SVELTE_FUI_FIELD_CONTEXT_KEY, context); 23 | } 24 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/field-message-error.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/field-message-info.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/field-message-success.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/field-message-warning.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/field-message.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | {#if open} 14 |
18 | 19 |
20 | {/if} 21 | 22 | 59 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/field.stories.svelte: -------------------------------------------------------------------------------- 1 | 50 | 51 | 70 | 71 | 72 | 73 |
74 |
75 | 76 | 77 | This an error message 78 | 79 | 80 | 81 | 82 | This a warning message 83 | 84 | 85 | 86 | 87 | This a success message 88 | 89 | 90 | 91 | 92 | This a simple message 93 | 94 | 95 | 96 | 97 | This an info message 98 | 99 |
100 |
101 |
102 |
103 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/field.svelte: -------------------------------------------------------------------------------- 1 | 60 | 61 |
62 | 63 | 64 |
65 | 66 | 99 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Field } from './field.svelte'; 2 | export { default as FieldMessage } from './field-message.svelte'; 3 | export { default as ValidationMessage } from './field-message.svelte'; 4 | export { default as FieldMessageError } from './field-message-error.svelte'; 5 | export { default as FieldMessageSuccess } from './field-message-success.svelte'; 6 | export { default as FieldMessageWarning } from './field-message-warning.svelte'; 7 | export { default as FieldMessageInfo } from './field-message-info.svelte'; 8 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/types,.ts: -------------------------------------------------------------------------------- 1 | export type FieldState = 'none' | 'error' | 'warning' | 'success' | undefined; 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/icon/icon.stories.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 |
29 |
30 |
31 | -------------------------------------------------------------------------------- /packages/core/src/lib/icon/icon.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 | 13 |
14 | 15 | 24 | -------------------------------------------------------------------------------- /packages/core/src/lib/icon/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Icon} from './icon.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/add-regular.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/alert-regular.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/arrow-up-regular.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/checkmark-circle-filled.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/checkmark-filled.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/chevron-down-regular.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/chevron-right.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/error-circle-filled.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/info-filled.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/person-regular.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/warning-filled.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app'; 2 | export * from './avatar'; 3 | export * from './button'; 4 | export * from './checkbox'; 5 | export * from './dropdown'; 6 | export * from './menu'; 7 | export * from './combobox'; 8 | export * from './input'; 9 | export * from './icon'; 10 | export * from './text'; 11 | export * from './label'; 12 | export * from './tooltip'; 13 | export * from './card'; 14 | export * from './divider'; 15 | // export * from './theme' 16 | export * from './switch'; 17 | export * from './radio'; 18 | export * from './slider'; 19 | export * from './dialog'; 20 | export * from './accordion'; 21 | export * from './link'; 22 | export * from './spinner'; 23 | export * from './field'; 24 | export * from './layout'; 25 | -------------------------------------------------------------------------------- /packages/core/src/lib/input/context.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | import { type Readable, type Writable } from 'svelte/store'; 3 | 4 | export const FUI_INPUT_CONTEXT_KEY = 'fui-context/input'; 5 | 6 | export type FluentInputContext = {}; 7 | 8 | export function getFluentInputContext() { 9 | return getContext(FUI_INPUT_CONTEXT_KEY) as FluentInputContext; 10 | } 11 | 12 | export function setFluentInputContext(context: FluentInputContext): FluentInputContext { 13 | return setContext(FUI_INPUT_CONTEXT_KEY, context); 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/src/lib/input/index.ts: -------------------------------------------------------------------------------- 1 | // import InputElement from './input-element.svelte'; 2 | // import InputRoot from './input-root.svelte'; 3 | 4 | export { default as Input } from './input.svelte'; 5 | export { default as InputSkin } from './input-root.svelte'; 6 | 7 | // export const Input = { 8 | // Root: InputRoot, 9 | // Element: InputElement 10 | // } 11 | -------------------------------------------------------------------------------- /packages/core/src/lib/input/input-element.svelte: -------------------------------------------------------------------------------- 1 | 60 | 61 | 86 | -------------------------------------------------------------------------------- /packages/core/src/lib/input/input.stories.svelte: -------------------------------------------------------------------------------- 1 | 23 | 24 | 43 | 44 | 45 | 46 |
47 | 48 |
49 |
50 |
51 | 52 | 53 | 54 |
55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | An input with a decorative icon in the before slot. 63 |
64 | 65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | An input with a button in the after slot. 73 |
74 | 75 |
76 | 77 | 78 | $ 79 | .00 80 | 81 | An input with a presentational value in the before slot and another presentational value in the after slot. 84 |
85 |
86 |
87 |
88 | -------------------------------------------------------------------------------- /packages/core/src/lib/input/input.svelte: -------------------------------------------------------------------------------- 1 | 43 | 44 | 53 | {#if $$slots.before} 54 |
55 | 56 |
57 | {/if} 58 | 59 | 86 | 87 | {#if $$slots.after} 88 |
89 | 90 |
91 | {/if} 92 |
93 | -------------------------------------------------------------------------------- /packages/core/src/lib/input/types.ts: -------------------------------------------------------------------------------- 1 | import type { HTMLInputTypeAttribute } from 'svelte/elements'; 2 | 3 | export type InputType = HTMLInputTypeAttribute; 4 | export type InputSize = 'sm' | 'md' | 'lg'; 5 | 6 | export type ExternalContext = { invalid: boolean; required: boolean; size: InputSize }; 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/internal/context.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | 3 | const FLUENT_CONTEXT_KEY = '@fui/context'; 4 | 5 | export function getFluentContext(id = '', ...segments: string[]) { 6 | const key = [FLUENT_CONTEXT_KEY, id, ...segments].filter(Boolean).join('/'); 7 | return getContext(key); 8 | } 9 | 10 | export function setFluentContext(context: T, id = '', ...segments: string[]) { 11 | const key = [FLUENT_CONTEXT_KEY, id, ...segments].filter(Boolean).join('/'); 12 | 13 | return setContext(key, context); 14 | } 15 | 16 | export function getSharedContext(...segments: string[]) { 17 | return getFluentContext('shared', ...segments); 18 | } 19 | 20 | export function setSharedContext(context: T, ...segments: string[]) { 21 | return setFluentContext(context, 'shared', ...segments); 22 | } 23 | 24 | export function mergeContext(...contexts: (T | undefined)[]) { 25 | return contexts.filter(Boolean).reduce((acc, val) => ({ ...acc, ...val }), {} as T); 26 | } 27 | -------------------------------------------------------------------------------- /packages/core/src/lib/internal/transition.ts: -------------------------------------------------------------------------------- 1 | export const DURATION = { 2 | QUICK: 50, 3 | FAST: 100, 4 | NORMAL: 200, 5 | SMOOTH: 300, 6 | SLOW: 400, 7 | DRAGGING: 500 8 | }; 9 | -------------------------------------------------------------------------------- /packages/core/src/lib/internal/utils.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from 'nanoid'; 2 | 3 | export function safe(value: R, resolve: () => S, reject: () => T) { 4 | if (!value) { 5 | return reject(); 6 | } 7 | 8 | return resolve(); 9 | } 10 | 11 | export function fid(namespace = '') { 12 | return ['f', '-', namespace, namespace ? '-' : '', nanoid(8)].join(''); 13 | } 14 | -------------------------------------------------------------------------------- /packages/core/src/lib/label/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Label } from './label.svelte'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /packages/core/src/lib/label/label.stories.svelte: -------------------------------------------------------------------------------- 1 | 55 | 56 | 75 | 76 | 77 | 78 |
79 | 80 |
81 |
82 |
83 | -------------------------------------------------------------------------------- /packages/core/src/lib/label/label.svelte: -------------------------------------------------------------------------------- 1 | 31 | 32 | 48 | 49 | 74 | -------------------------------------------------------------------------------- /packages/core/src/lib/label/types.ts: -------------------------------------------------------------------------------- 1 | import type { HTMLAttributes } from 'svelte/elements'; 2 | 3 | export type LabelSize = 'sm' | 'md' | 'lg'; 4 | 5 | export type LabelProps = HTMLAttributes & { 6 | disabled?: boolean; 7 | required?: boolean | string; 8 | size?: LabelSize; 9 | class?: string; 10 | }; -------------------------------------------------------------------------------- /packages/core/src/lib/layout/context.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/209b44b3143be8c8d8a6a6a8f112e7423318e396/packages/core/src/lib/layout/context.ts -------------------------------------------------------------------------------- /packages/core/src/lib/layout/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Layout } from './layout.svelte'; 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/layout/layout.stories.svelte: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/209b44b3143be8c8d8a6a6a8f112e7423318e396/packages/core/src/lib/layout/layout.stories.svelte -------------------------------------------------------------------------------- /packages/core/src/lib/layout/layout.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 |
25 | 26 |
27 | -------------------------------------------------------------------------------- /packages/core/src/lib/link/Link.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 29 | 30 | 31 | 32 | 100 | -------------------------------------------------------------------------------- /packages/core/src/lib/link/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Link} from './Link.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/link/link.stories.svelte: -------------------------------------------------------------------------------- 1 | 50 | 51 | 70 | 71 | 72 | 73 |
74 |

Hello World ! Svelte is more than a Framework !

75 |
76 |
77 |
78 | -------------------------------------------------------------------------------- /packages/core/src/lib/menu/context-item.ts: -------------------------------------------------------------------------------- 1 | import type { Writable } from 'svelte/store'; 2 | import { getFluentContext, setFluentContext } from '@svelte-fui/core/internal/context'; 3 | 4 | export const FUI_MENU_ITEM_NAMESPACE = 'menu/item'; 5 | 6 | export type MenuItemContext = { 7 | id: Writable; 8 | open: Writable; 9 | close(): void; 10 | }; 11 | 12 | export function getMenuItemContext() { 13 | return getFluentContext(FUI_MENU_ITEM_NAMESPACE); 14 | } 15 | 16 | export function setMenuItemContext(context: MenuItemContext) { 17 | return setFluentContext(context, FUI_MENU_ITEM_NAMESPACE); 18 | } 19 | -------------------------------------------------------------------------------- /packages/core/src/lib/menu/context-root.ts: -------------------------------------------------------------------------------- 1 | import type { Writable } from 'svelte/store'; 2 | import { getFluentContext, setFluentContext } from '@svelte-fui/core/internal/context'; 3 | 4 | export const FUI_MENU_NAMESPACE = 'menu'; 5 | 6 | export type MenuContext = { 7 | open: Writable; 8 | triggerElement: Writable; 9 | itemsActive: Writable>; 10 | elements: { 11 | trigger: Writable; 12 | menu: Writable; 13 | anchor: Writable; 14 | }; 15 | close(): void; 16 | }; 17 | 18 | export function getMenuContext() { 19 | return getFluentContext(FUI_MENU_NAMESPACE); 20 | } 21 | 22 | export function setMenuContext(context: MenuContext) { 23 | return setFluentContext(context, FUI_MENU_NAMESPACE); 24 | } 25 | -------------------------------------------------------------------------------- /packages/core/src/lib/menu/index.ts: -------------------------------------------------------------------------------- 1 | import MenuDivider from './menu-divider.svelte'; 2 | import MenuGroup from './menu-group.svelte'; 3 | import MenuItem from './menu-item.svelte'; 4 | import MenuRoot from './menu-root.svelte'; 5 | import MenuTrigger from './menu-trigger.svelte'; 6 | 7 | export * from './context-root'; 8 | export * from './types' 9 | 10 | export const Menu = { 11 | Root: MenuRoot, 12 | Item: MenuItem, 13 | Group: MenuGroup, 14 | Divider: MenuDivider, 15 | Trigger: MenuTrigger 16 | }; 17 | -------------------------------------------------------------------------------- /packages/core/src/lib/menu/menu-divider.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/core/src/lib/menu/menu-group.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 | 13 |
14 | -------------------------------------------------------------------------------- /packages/core/src/lib/menu/menu-item.svelte: -------------------------------------------------------------------------------- 1 | 82 | 83 | 95 | 96 | 107 | -------------------------------------------------------------------------------- /packages/core/src/lib/menu/menu-trigger.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | -------------------------------------------------------------------------------- /packages/core/src/lib/menu/types.ts: -------------------------------------------------------------------------------- 1 | import type { HTMLAttributes } from 'svelte/elements'; 2 | import type { Placement } from '@floating-ui/dom'; 3 | 4 | export type MenuRootProps = HTMLAttributes & { 5 | open?: boolean; 6 | discover?: boolean; 7 | offset?: number; 8 | placements?: Placement[]; 9 | }; 10 | 11 | export type MenuItemProps = HTMLAttributes & { 12 | open?: boolean; 13 | }; 14 | 15 | export type MenuGroupProps = HTMLAttributes; 16 | 17 | export type MenuDividerProps = HTMLAttributes; 18 | -------------------------------------------------------------------------------- /packages/core/src/lib/popover/context.ts: -------------------------------------------------------------------------------- 1 | import { type Writable } from 'svelte/store'; 2 | import { getFluentContext, setFluentContext } from '../internal/context'; 3 | 4 | const FUI_POPOVER_CONTEXT_ID = 'popover'; 5 | 6 | export type PopoverContext = { 7 | open: Writable; 8 | referenceElement: Writable; 9 | }; 10 | 11 | export function getPopoverContext(): PopoverContext | undefined { 12 | return getFluentContext(FUI_POPOVER_CONTEXT_ID); 13 | } 14 | 15 | export function setPopoverContext(context: PopoverContext) { 16 | return setFluentContext(context, FUI_POPOVER_CONTEXT_ID); 17 | } 18 | -------------------------------------------------------------------------------- /packages/core/src/lib/popover/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Popover } from './popover.svelte'; 2 | export * from './context'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /packages/core/src/lib/popover/popover.stories.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 28 | 29 | 30 | 31 | 57 | 58 | 59 |
60 |
Hello World!
61 |
62 |
63 |
64 |
65 | -------------------------------------------------------------------------------- /packages/core/src/lib/popover/popover.svelte: -------------------------------------------------------------------------------- 1 | 58 | 59 | {#if $layouts['overlay'].element && $reference_element_store && open} 60 |
{ 71 | referenceElement = new_reference; 72 | }, 73 | onChange: (params) => { 74 | dx = params.dx; 75 | dy = params.dy; 76 | }, 77 | onMount: () => { 78 | mounted = true; 79 | } 80 | }} 81 | use:clickOutside={{ 82 | callback: onclick_outside, 83 | exclude: [referenceElement ?? '', ''] 84 | }} 85 | > 86 | {#if mounted} 87 | 88 | {/if} 89 |
90 | {/if} 91 | 92 | 97 | -------------------------------------------------------------------------------- /packages/core/src/lib/popover/types.ts: -------------------------------------------------------------------------------- 1 | import type { HTMLAttributes } from 'svelte/elements'; 2 | import type { Alignment, Placement } from '@floating-ui/dom'; 3 | 4 | export type PopoverProps = HTMLAttributes & { 5 | open?: boolean; 6 | referenceElement?: HTMLElement; 7 | placements?: Placement[]; 8 | alignment?: Alignment; 9 | offset?: number; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/core/src/lib/radio/context.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | import { type Writable } from 'svelte/store'; 3 | import type { Layout } from './types'; 4 | 5 | const key = 'fui_radio_group_context'; 6 | 7 | export type RadioGroupContext = { 8 | disabled$: Writable; 9 | required$: Writable; 10 | value$: Writable; 11 | name$: Writable; 12 | layout$: Writable; 13 | 14 | methods: { 15 | select: (value: string) => void; 16 | }; 17 | }; 18 | 19 | export function getRadioGroupContext() { 20 | return getContext(key) as RadioGroupContext; 21 | } 22 | 23 | export function setRadioGroupContext(context: RadioGroupContext): RadioGroupContext { 24 | return setContext(key, context); 25 | } 26 | -------------------------------------------------------------------------------- /packages/core/src/lib/radio/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Radio } from './radio.svelte'; 2 | export { default as RadioGroup } from './radio-group.svelte'; 3 | -------------------------------------------------------------------------------- /packages/core/src/lib/radio/radio-group.stories.svelte: -------------------------------------------------------------------------------- 1 | 49 | 50 | 72 | 73 | 74 | 75 |
76 | 77 | console.log(e)}>Apple 78 | console.log(e)}>Orange 79 | console.log(e)}>Banana 80 | console.log(e)}>Pear 81 | 82 |
83 |
84 |
85 | -------------------------------------------------------------------------------- /packages/core/src/lib/radio/radio-group.svelte: -------------------------------------------------------------------------------- 1 | 35 | 36 |
37 | 38 |
39 | 40 | 49 | -------------------------------------------------------------------------------- /packages/core/src/lib/radio/radio.stories.svelte: -------------------------------------------------------------------------------- 1 | 57 | 58 | 77 | 78 | 79 | 80 |
81 | Apple 82 | Orange 83 | Banana 84 | Pear 85 |
86 |
87 |
88 | -------------------------------------------------------------------------------- /packages/core/src/lib/radio/types.ts: -------------------------------------------------------------------------------- 1 | export type Layout = 'vertical' | 'horizontal' | 'stacked-horizontal' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/slider/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Slider } from './slider.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/slider/slider.stories.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 41 | 42 |
43 |
44 | 45 |
46 |
47 |
48 |
49 | -------------------------------------------------------------------------------- /packages/core/src/lib/spinner/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Spinner } from './spinner.svelte'; 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/spinner/spinner-default-icon.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 73 | -------------------------------------------------------------------------------- /packages/core/src/lib/spinner/spinner.stories.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 41 | 42 |
43 | Loding Data... 44 |
45 |
46 |
47 | -------------------------------------------------------------------------------- /packages/core/src/lib/styles/root.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | img { 7 | width: unset; 8 | height: unset; 9 | max-width: initial; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/switch/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Switch } from './switch.svelte'; 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/switch/switch.stories.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
56 |
57 |
58 |
59 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/context.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | import { type Readable, type Writable, readonly, writable } from 'svelte/store'; 3 | import { type RowStore } from './store'; 4 | import type { SortingDirection, TableSize } from './type'; 5 | 6 | export const SVELTE_FUI_TABLE_CONTEXT_KEY = 'svelte-fui-table-context-key'; 7 | 8 | export type TableContext = { 9 | sortable$: Writable; 10 | size$: Writable; 11 | sorting$: Writable<[key: (d: any) => any, direction: SortingDirection] | undefined>; 12 | allRows$: Readable; 13 | selectedKeys$: Readable; 14 | mountRow: (store: RowStore) => () => void; 15 | }; 16 | 17 | export function getTableContext(): TableContext { 18 | return getContext(SVELTE_FUI_TABLE_CONTEXT_KEY); 19 | } 20 | 21 | export function setTableContext() { 22 | const allRows$ = writable([]); 23 | const selectedKeys$ = writable([]); 24 | 25 | const context: TableContext = { 26 | sortable$: writable(false), 27 | size$: writable('md'), 28 | sorting$: writable(undefined), 29 | allRows$: readonly(allRows$), 30 | selectedKeys$: readonly(selectedKeys$), 31 | mountRow 32 | }; 33 | 34 | return setContext(SVELTE_FUI_TABLE_CONTEXT_KEY, context); 35 | 36 | function mountRow(store: RowStore) { 37 | allRows$.update((old) => [...old, store]); 38 | 39 | const unsubscribe = store.selected$.subscribe((value) => { 40 | if (value) { 41 | selectedKeys$.update((old) => [...new Set([...old, store.id])]); 42 | } else { 43 | selectedKeys$.update((old) => old.filter((d) => d !== store.id)); 44 | } 45 | }); 46 | 47 | return () => { 48 | unsubscribe(); 49 | destroyRow(store.id); 50 | }; 51 | } 52 | 53 | function destroyRow(id: string) { 54 | allRows$.update((old) => old.filter((d) => d !== id)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Table } from './table-root.svelte'; 2 | export { default as Th } from './th.svelte'; 3 | export { default as Td } from './td.svelte'; 4 | export { default as Tr } from './tr/tr.svelte'; 5 | export { default as TdSelection } from './td-selection.svelte'; 6 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/store.ts: -------------------------------------------------------------------------------- 1 | import { type Updater, type Writable, writable } from 'svelte/store'; 2 | 3 | export type RowStore = { 4 | id: string; 5 | data: T; 6 | selected$: Writable & { value: boolean }; 7 | }; 8 | 9 | export function rowStore(id: string, data: T) { 10 | let selected = false; 11 | 12 | const selected$ = writable(selected); 13 | 14 | return { 15 | id, 16 | data, 17 | selected$: { 18 | subscribe: selected$.subscribe, 19 | set(value: boolean) { 20 | return selected$.set((selected = value)); 21 | }, 22 | update(updater: Updater) { 23 | return selected$.update((val) => { 24 | return (selected = updater(val)); 25 | }); 26 | }, 27 | 28 | get value() { 29 | return selected; 30 | }, 31 | set value(value: boolean) { 32 | this.set(value); 33 | } 34 | } 35 | }; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/table-root.svelte: -------------------------------------------------------------------------------- 1 | 34 | 35 | 36 | 37 |
38 | 39 | 52 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/td-selection.svelte: -------------------------------------------------------------------------------- 1 | 59 | 60 | 67 | 68 | 107 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/td.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 | 33 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/th.svelte: -------------------------------------------------------------------------------- 1 | 70 | 71 | 72 |
73 | 74 | 75 | {#if sortable && $activeSort$} 76 |
77 | 78 | 79 | 80 |
81 | {/if} 82 |
83 | 84 | 85 | 110 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/tr/context.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | 3 | export const SVELTE_FUI_TABLE_ROW_CONTEXT_KEY = 'svelte-fui::table-row-context-key'; 4 | 5 | export type TableContext = { 6 | id: string | undefined; 7 | header: boolean; 8 | }; 9 | 10 | export function getTableRowContext(): TableContext { 11 | return getContext(SVELTE_FUI_TABLE_ROW_CONTEXT_KEY); 12 | } 13 | 14 | export function setTableRowContext() { 15 | const context: TableContext = { 16 | id: undefined, 17 | header: false 18 | }; 19 | 20 | return setContext(SVELTE_FUI_TABLE_ROW_CONTEXT_KEY, context); 21 | } 22 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/tr/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tr} from './tr.svelte' 2 | export * from './context' 3 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/type.ts: -------------------------------------------------------------------------------- 1 | export type TableSize = 'xs' | 'sm' | 'md'; 2 | export type SortingDirection = 'ascending' | 'descending'; 3 | 4 | export type RowItem = { 5 | id: string 6 | selected: boolean; 7 | data: T; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/core/src/lib/tailwindcss/colors_shared.js: -------------------------------------------------------------------------------- 1 | /* Names of colors used in shared color palette alias tokens for status. */ 2 | export const statusSharedColorNames = [ 3 | 'red', 4 | 'green', 5 | 'darkOrange', 6 | 'yellow', 7 | 'berry', 8 | 'lightGreen', 9 | 'marigold', 10 | ] 11 | -------------------------------------------------------------------------------- /packages/core/src/lib/tailwindcss/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './tailwind.config'; 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/tailwindcss/utils/index.ts: -------------------------------------------------------------------------------- 1 | export function tailwindColorify(name: string, colors: Record) { 2 | return Object.entries(colors).reduce((acc, [key, value]) => { 3 | acc[[name, key].join('-')] = value; 4 | 5 | return acc; 6 | }, {}); 7 | } 8 | -------------------------------------------------------------------------------- /packages/core/src/lib/text/index.ts: -------------------------------------------------------------------------------- 1 | export {default as Text} from './text.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/text/text.stories.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 41 | 42 |
43 | This is an example of the Text component's usage. 44 |
45 |
46 |
47 | -------------------------------------------------------------------------------- /packages/core/src/lib/text/text.svelte: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | 100 | -------------------------------------------------------------------------------- /packages/core/src/lib/tokens/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/209b44b3143be8c8d8a6a6a8f112e7423318e396/packages/core/src/lib/tokens/index.ts -------------------------------------------------------------------------------- /packages/core/src/lib/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tooltip } from './tooltip.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/tooltip/tooltip.stories.svelte: -------------------------------------------------------------------------------- 1 | 55 | 56 | 75 | 76 | 77 | 78 |
79 | 80 | 81 | 82 | Hello from the other side! [slotted] 83 | 84 |
85 |
86 |
87 | -------------------------------------------------------------------------------- /packages/core/src/lib/utils/context.ts: -------------------------------------------------------------------------------- 1 | type Builder = () => any; 2 | 3 | export function buildContext(context: Partial = {}, builders: Record) { 4 | const keys = new Set(Object.keys(builders)) as Set; 5 | 6 | Object.keys(context).forEach((key) => keys.delete(key)); 7 | 8 | for (const key of keys) { 9 | context[key] = builders[key](); 10 | } 11 | 12 | return context as T; 13 | } 14 | -------------------------------------------------------------------------------- /packages/core/src/lib/utils/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/209b44b3143be8c8d8a6a6a8f112e7423318e396/packages/core/src/lib/utils/index.ts -------------------------------------------------------------------------------- /packages/core/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 |

Welcome to your library project

2 |

Create your package using @sveltejs/package and preview/showcase your work with SvelteKit

3 |

Visit kit.svelte.dev to read the documentation

4 | -------------------------------------------------------------------------------- /packages/core/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/209b44b3143be8c8d8a6a6a8f112e7423318e396/packages/core/static/favicon.png -------------------------------------------------------------------------------- /packages/core/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 | import path from 'path'; 4 | 5 | /** @type {import('@sveltejs/kit').Config} */ 6 | const config = { 7 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 8 | // for more information about preprocessors 9 | preprocess: vitePreprocess(), 10 | 11 | kit: { 12 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 13 | // If your environment is not supported, or you settled on a specific environment, switch out the adapter. 14 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 15 | adapter: adapter(), 16 | alias: { 17 | '@svelte-fui/core': path.resolve('./src/lib') 18 | } 19 | } 20 | }; 21 | 22 | export default config; 23 | -------------------------------------------------------------------------------- /packages/core/tailwind.config.js: -------------------------------------------------------------------------------- 1 | import { tailwindcssConfig } from '../tailwindcss/src' 2 | 3 | /** @type {import('tailwindcss').Config} */ 4 | export default { 5 | presets: [tailwindcssConfig], 6 | content: ['./src/**/*.{html,js,svelte, stories.svelte, ts}'], 7 | 8 | } -------------------------------------------------------------------------------- /packages/core/tests/test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from '@playwright/test'; 2 | 3 | test('home page has expected h1', async ({ page }) => { 4 | await page.goto('/'); 5 | await expect(page.locator('h1')).toBeVisible(); 6 | }); 7 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "module": "ES2015", 13 | "moduleResolution": "Bundler", 14 | "composite": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/core/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"version":"5.0.4"} -------------------------------------------------------------------------------- /packages/core/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vitest/config'; 3 | import Icons from 'unplugin-icons/vite' 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | sveltekit(), 8 | Icons({ 9 | compiler: 'svelte', 10 | autoInstall: true 11 | }) 12 | ], 13 | test: { 14 | include: ['src/**/*.{test,spec}.{js,ts}'] 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /packages/tailwindcss/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /packages/tailwindcss/README.md: -------------------------------------------------------------------------------- 1 | # @svelte-fui/tailwindcss 2 | 3 | This project's Tailwind CSS preset for the Fluent Design System makes it simple to create modern, accessible, and customizable user interfaces. This integration enables developers to construct the desired look and feel without spending hours writing code. Using Tailwind's predefined classes, developers can readily modify the application's colors, fonts, sizes, and other design elements. 4 | 5 | 6 | # Usage 7 | 8 | First, install `@svelte-fui/tailwindcss`: 9 | 10 | ```shell 11 | // pnpm 12 | pnpm install @svelte-fui/tailwindcss 13 | 14 | //npm 15 | npm install @svelte-fui/tailwindcss 16 | ``` 17 | 18 | Then, you add it to your tailwindcss's presets array: 19 | 20 | ```js 21 | // tailwindcss.config.js 22 | 23 | import { fuiPreset } from '@svelte-fui/tailwindcss'; 24 | 25 | /** @type {import('tailwindcss').Config} */ 26 | export default { 27 | presets: [fuiPreset], 28 | content: ['./src/**/*.{html,js,svelte, stories.svelte, ts}'] 29 | }; 30 | ``` 31 | 32 | ```html 33 | 36 | 37 | 38 |
This a simple label
39 | 40 |
41 | ``` 42 | -------------------------------------------------------------------------------- /packages/tailwindcss/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@svelte-fui/tailwindcss", 3 | "version": "0.1.9", 4 | "description": "", 5 | "type": "module", 6 | "sideEffects": false, 7 | "scripts": { 8 | "build": "npx tsc" 9 | }, 10 | "author": "", 11 | "license": "MIT", 12 | "files": [ 13 | "dist", 14 | "!dist/**/*.stories.svelte" 15 | ], 16 | "devDependencies": { 17 | "tailwindcss": "^3.3.1", 18 | "tslib": "^2.5.0", 19 | "typescript": "^5.0.2", 20 | "vite": "^5.1.0" 21 | }, 22 | "dependencies": { 23 | "@svelte-fui/theme": "^0.1.3" 24 | }, 25 | "peerDependencies": { 26 | "@svelte-fui/theme": "^0.1.3", 27 | "tailwindcss": "^3.3.1" 28 | }, 29 | "exports": { 30 | ".": { 31 | "types": "./dist/index.d.ts", 32 | "svelte": "./dist/index.js", 33 | "default": "./dist/index.js" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/tailwindcss/src/colors_shared.ts: -------------------------------------------------------------------------------- 1 | /* Names of colors used in shared color palette alias tokens for status. */ 2 | export const statusSharedColorNames = [ 3 | 'red', 4 | 'green', 5 | 'darkOrange', 6 | 'yellow', 7 | 'berry', 8 | 'lightGreen', 9 | 'marigold', 10 | ] 11 | -------------------------------------------------------------------------------- /packages/tailwindcss/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @deprecated Use `fuiPreset` instead. 3 | */ 4 | export { default as tailwindcssConfig, defaultTheme } from './config'; 5 | export { default as fuiPreset } from './config'; 6 | -------------------------------------------------------------------------------- /packages/tailwindcss/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export function tailwindColorify(name: string, colors: Record) { 2 | return Object.entries(colors).reduce((acc, [key, value]) => { 3 | acc[[name, key].join('-')] = value; 4 | 5 | return acc; 6 | }, {} as Record); 7 | } 8 | -------------------------------------------------------------------------------- /packages/tailwindcss/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", // Or another suitable ECMAScript target 4 | "module": "ESNext", // Or your preferred module system (e.g., 'ES2020', 'ESNext') 5 | "declaration": true, // This is the key to generate .d.ts files 6 | "outDir": "./dist", // Optional: Specify the output directory 7 | "rootDir": "./src", // Optional: Specify where your source .ts files live 8 | "moduleResolution": "Bundler", 9 | "skipLibCheck": true 10 | }, 11 | "include": ["./src/**/*.ts", "./src/**/*.js"], // Make sure it includes the path to your TypeScript source files 12 | "exclude": ["./node_modules"] 13 | } 14 | -------------------------------------------------------------------------------- /packages/tailwindcss/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import path from 'path' 3 | import pkg from './package.json' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | build:{ 8 | lib:{ 9 | formats:['es'], 10 | entry: path.resolve('./src/index.ts'), 11 | name: pkg.name, 12 | fileName:'index' 13 | } 14 | }, 15 | optimizeDeps: { 16 | include:['@svelte-fui/theme'] 17 | } 18 | }) 19 | -------------------------------------------------------------------------------- /packages/theme/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /packages/theme/.npmignore: -------------------------------------------------------------------------------- 1 | dist/*.stories.svelte 2 | -------------------------------------------------------------------------------- /packages/theme/README.md: -------------------------------------------------------------------------------- 1 | # @svelte-fui/theme 2 | 3 | The `@svelte-fui/theme` package empowers users to craft tailor-made themes for their Svelte Fluent UI applications. 4 | 5 | This grants them effortless control over the visual aesthetics of their app, while maintaining seamless integration with Fluent UI's core components. 6 | 7 | # Usage 8 | 9 | Please proceed with the package installation. 10 | 11 | ```shell 12 | // pnpm 13 | pnpm install @svelte-fui/theme 14 | 15 | //npm 16 | npm install @svelte-fui/theme 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/theme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@svelte-fui/theme", 3 | "version": "0.1.4", 4 | "description": "", 5 | "type": "module", 6 | "sideEffects": false, 7 | "scripts": { 8 | "build": "npx tsc" 9 | }, 10 | "files": [ 11 | "./dist" 12 | ], 13 | "author": "", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "@sveltejs/package": "^2.0.2", 17 | "@sveltejs/vite-plugin-svelte": "^2.0.3", 18 | "@tsconfig/svelte": "^4.0.1", 19 | "lodash-es": "^4.17.21", 20 | "svelte": "^4.0.0", 21 | "svelte-check": "^2.10.3", 22 | "tslib": "^2.5.0", 23 | "typescript": "^5.0.2", 24 | "vite": "^5.1.0" 25 | }, 26 | "peerDependencies": { 27 | "lodash-es": "^4.17.21" 28 | }, 29 | "exports": { 30 | ".": { 31 | "types": "./dist/index.d.ts", 32 | "svelte": "./dist/index.js", 33 | "default": "./dist/index.js" 34 | }, 35 | "./global/colors": { 36 | "types": "./dist/global/colors.d.ts", 37 | "svelte": "./dist/global/colors.js", 38 | "default": "./dist/global/colors.js" 39 | }, 40 | "./global/brandColors": { 41 | "types": "./dist/global/brandColors.d.ts", 42 | "svelte": "./dist/global/brandColors.js", 43 | "default": "./dist/global/brandColors.js" 44 | }, 45 | "./global/duration": { 46 | "types": "./dist/global/duration.d.ts", 47 | "svelte": "./dist/global/duration.js", 48 | "default": "./dist/global/duration.js" 49 | }, 50 | "./global/fonts": { 51 | "types": "./dist/global/fonts.d.ts", 52 | "svelte": "./dist/global/fonts.js", 53 | "default": "./dist/global/fonts.js" 54 | }, 55 | "./global/shadow": { 56 | "types": "./dist/global/shadow.d.ts", 57 | "svelte": "./dist/global/shadow.js", 58 | "default": "./dist/global/shadow.js" 59 | }, 60 | "./global/spacings": { 61 | "types": "./dist/global/spacings.d.ts", 62 | "svelte": "./dist/global/spacings.js", 63 | "default": "./dist/global/spacings.js" 64 | }, 65 | "./global/timingFunctions": { 66 | "types": "./dist/global/timingFunctions.d.ts", 67 | "svelte": "./dist/global/timingFunctions.js", 68 | "default": "./dist/global/timingFunctions.js" 69 | }, 70 | "./utils": { 71 | "types": "./dist/utils/index.d.ts", 72 | "svelte": "./dist/utils/index.js", 73 | "default": "./dist/utils/index.js" 74 | }, 75 | "./types": { 76 | "types": "./dist/types.d.ts" 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /packages/theme/src/alias/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/209b44b3143be8c8d8a6a6a8f112e7423318e396/packages/theme/src/alias/index.ts -------------------------------------------------------------------------------- /packages/theme/src/global/brandColors.ts: -------------------------------------------------------------------------------- 1 | import type { BrandVariants } from '../types'; 2 | 3 | export const brandWeb: BrandVariants = { 4 | '10': `#061724`, 5 | '20': `#082338`, 6 | '30': `#0a2e4a`, 7 | '40': `#0c3b5e`, 8 | '50': `#0e4775`, 9 | '60': `#0f548c`, 10 | '70': `#115ea3`, 11 | '80': `#0f6cbd`, 12 | '90': `#2886de`, 13 | '100': `#479ef5`, 14 | '110': `#62abf5`, 15 | '120': `#77b7f7`, 16 | '130': `#96c6fa`, 17 | '140': `#b4d6fa`, 18 | '150': `#cfe4fa`, 19 | '160': `#ebf3fc`, 20 | }; 21 | 22 | export const brandTeams: BrandVariants = { 23 | '10': `#2b2b40`, 24 | '20': `#2f2f4a`, 25 | '30': `#333357`, 26 | '40': `#383966`, 27 | '50': `#3d3e78`, 28 | '60': `#444791`, 29 | '70': `#4f52b2`, 30 | '80': `#5b5fc7`, 31 | '90': `#7579eb`, 32 | '100': `#7f85f5`, 33 | '110': `#9299f7`, 34 | '120': `#aab1fa`, 35 | '130': `#b6bcfa`, 36 | '140': `#c5cbfa`, 37 | '150': `#dce0fa`, 38 | '160': `#e8ebfa`, 39 | }; 40 | 41 | export const brandOffice: BrandVariants = { 42 | '10': `#29130b`, 43 | '20': `#4d2415`, 44 | '30': `#792000`, 45 | '40': `#99482b`, 46 | '50': `#a52c00`, 47 | '60': `#c33400`, 48 | '70': `#e06a3f`, 49 | '80': `#d83b01`, 50 | '90': `#dd4f1b`, 51 | '100': `#fe7948`, 52 | '110': `#ff865a`, 53 | '120': `#ff9973`, 54 | '130': `#e8825d`, 55 | '140': `#ffb498`, 56 | '150': `#f4beaa`, 57 | '160': `#f9dcd1`, 58 | }; 59 | -------------------------------------------------------------------------------- /packages/theme/src/global/colorPalette.ts: -------------------------------------------------------------------------------- 1 | import { 2 | anchor, 3 | beige, 4 | berry, 5 | blue, 6 | brass, 7 | brown, 8 | cornflower, 9 | cranberry, 10 | darkGreen, 11 | darkOrange, 12 | darkRed, 13 | forest, 14 | gold, 15 | grape, 16 | green, 17 | lavender, 18 | lightGreen, 19 | lightTeal, 20 | lilac, 21 | magenta, 22 | marigold, 23 | mink, 24 | navy, 25 | peach, 26 | pink, 27 | platinum, 28 | plum, 29 | pumpkin, 30 | purple, 31 | red, 32 | royalBlue, 33 | seafoam, 34 | steel, 35 | teal, 36 | yellow 37 | } from './colors'; 38 | import type { PersonaSharedColors, StatusSharedColors } from '../types'; 39 | 40 | export const statusSharedColors: StatusSharedColors = { 41 | red, 42 | green, 43 | darkOrange, 44 | yellow, 45 | berry, 46 | lightGreen, 47 | marigold 48 | }; 49 | 50 | export const personaSharedColors: PersonaSharedColors = { 51 | darkRed, 52 | cranberry, 53 | pumpkin, 54 | peach, 55 | gold, 56 | brass, 57 | brown, 58 | forest, 59 | seafoam, 60 | darkGreen, 61 | lightTeal, 62 | teal, 63 | steel, 64 | blue, 65 | royalBlue, 66 | cornflower, 67 | navy, 68 | lavender, 69 | purple, 70 | grape, 71 | lilac, 72 | pink, 73 | magenta, 74 | plum, 75 | beige, 76 | mink, 77 | platinum, 78 | anchor 79 | }; 80 | -------------------------------------------------------------------------------- /packages/theme/src/global/curves.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/209b44b3143be8c8d8a6a6a8f112e7423318e396/packages/theme/src/global/curves.ts -------------------------------------------------------------------------------- /packages/theme/src/global/duration.ts: -------------------------------------------------------------------------------- 1 | export const durations = { 2 | 'ultra-fast': '50ms', 3 | 'faster': '100ms', 4 | 'fast': '150ms', 5 | 'normal': '200ms', 6 | 'slow': '300ms', 7 | 'slower': '400ms', 8 | 'ultra-slow': '500ms', 9 | } 10 | -------------------------------------------------------------------------------- /packages/theme/src/global/fonts.ts: -------------------------------------------------------------------------------- 1 | export const fontSizes = { 2 | 'base-100': '10px', 3 | 'base-200': '12px', 4 | 'base-300': '14px', 5 | 'base-400': '16px', 6 | 'base-500': '20px', 7 | 'base-600': '24px', 8 | 'hero-700': '28px', 9 | 'hero-800': '32px', 10 | 'hero-900': '40px', 11 | 'hero-1000': '68px', 12 | }; 13 | 14 | export const lineHeights = { 15 | 'base-100': '14px', 16 | 'base-200': '16px', 17 | 'base-300': '20px', 18 | 'base-400': '22px', 19 | 'base-500': '28px', 20 | 'base-600': '32px', 21 | 22 | 'hero-700': '36px', 23 | 'hero-800': '40px', 24 | 'hero-900': '52px', 25 | 'hero-1000': '92px', 26 | }; 27 | 28 | export const fontWeights = { 29 | 'regular': '400', 30 | 'medium': '500', 31 | 'semibold': '600', 32 | 'bold': '700', 33 | }; 34 | 35 | export const fontFamilies = { 36 | 'base': 37 | "'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif", 38 | 'monospace': "Consolas, 'Courier New', Courier, monospace", 39 | 'numeric': 40 | "Bahnschrift, 'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif", 41 | }; 42 | -------------------------------------------------------------------------------- /packages/theme/src/global/index.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/theme/src/global/shadow.ts: -------------------------------------------------------------------------------- 1 | export const shadow = { 2 | '2': 'var(--fui-shadow2)', 3 | '4': 'var(--fui-shadow4)', 4 | '8': 'var(--fui-shadow8)', 5 | '16': 'var(--fui-shadow16)', 6 | '28': 'var(--fui-shadow28)', 7 | '64': 'var(--fui-shadow64)', 8 | } 9 | 10 | export const shadowBrand = { 11 | '2Brand': 'var(--fui-shadow2Brand)', 12 | '4Brand': 'var(--fui-shadow4Brand)', 13 | '8Brand': 'var(--fui-shadow8Brand)', 14 | '16Brand': 'var(--fui-shadow16Brand)', 15 | '28Brand': 'var(--fui-shadow28Brand)', 16 | '64Brand': 'var(--fui-shadow64Brand)', 17 | } 18 | -------------------------------------------------------------------------------- /packages/theme/src/global/spacings.ts: -------------------------------------------------------------------------------- 1 | 2 | // Intentionally not exported! Use horizontalSpacings and verticalSpacings instead. 3 | export const spacings = { 4 | none: '0', 5 | xxs: '2px', 6 | xs: '4px', 7 | sNudge: '6px', 8 | s: '8px', 9 | mNudge: '10px', 10 | m: '12px', 11 | l: '16px', 12 | xl: '20px', 13 | xxl: '24px', 14 | xxxl: '32px', 15 | }; 16 | -------------------------------------------------------------------------------- /packages/theme/src/global/strokeWidth.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/209b44b3143be8c8d8a6a6a8f112e7423318e396/packages/theme/src/global/strokeWidth.ts -------------------------------------------------------------------------------- /packages/theme/src/global/timingFunctions.ts: -------------------------------------------------------------------------------- 1 | export const timingFunctions = { 2 | 'accelerate-max': 'cubic-bezier(1,0,1,1)', 3 | 'accelerate-mid': 'cubic-bezier(0.7,0,1,0.5)', 4 | 'accelerate-min': 'cubic-bezier(0.8,0,1,1)', 5 | 'decelerate-max': 'cubic-bezier(0,0,0,1)', 6 | 'decelerate-mid': 'cubic-bezier(0.1,0.9,0.2,1)', 7 | 'decelerate-min': 'cubic-bezier(0.33,0,0.1,1)', 8 | 'easy-ease-max': 'cubic-bezier(0.8,0,0.1,1)', 9 | 'easy-ease': 'cubic-bezier(0.33,0,0.67,1)', 10 | 'linear': 'cubic-bezier(0,0,1,1)', 11 | }; 12 | -------------------------------------------------------------------------------- /packages/theme/src/index.ts: -------------------------------------------------------------------------------- 1 | export type * from './types' 2 | -------------------------------------------------------------------------------- /packages/theme/src/sharedColorNames.ts: -------------------------------------------------------------------------------- 1 | /* Names of colors used in shared color palette alias tokens for status. */ 2 | export const statusSharedColorNames = ['red', 'green', 'darkOrange', 'yellow', 'berry', 'lightGreen', 'marigold'] as const; 3 | 4 | /* Names of colors used in shared color palette alias tokens for persona. */ 5 | export const personaSharedColorNames = [ 6 | 'darkRed', 7 | 'cranberry', 8 | 'pumpkin', 9 | 'peach', 10 | 'gold', 11 | 'brass', 12 | 'brown', 13 | 'forest', 14 | 'seafoam', 15 | 'darkGreen', 16 | 'lightTeal', 17 | 'teal', 18 | 'steel', 19 | 'blue', 20 | 'royalBlue', 21 | 'cornflower', 22 | 'navy', 23 | 'lavender', 24 | 'purple', 25 | 'grape', 26 | 'lilac', 27 | 'pink', 28 | 'magenta', 29 | 'plum', 30 | 'beige', 31 | 'mink', 32 | 'platinum', 33 | 'anchor' 34 | ] as const; 35 | 36 | /* Names of colors not used in alias tokens but produced by token pipeline as global color tokens. */ 37 | export const unusedSharedColorNames = [ 38 | 'burgundy', 39 | 'bronze', 40 | 'orange', 41 | 'darkBrown', 42 | 'lime', 43 | 'darkTeal', 44 | 'cyan', 45 | 'lightBlue', 46 | 'darkBlue', 47 | 'darkPurple', 48 | 'orchid', 49 | 'hotPink', 50 | 'silver', 51 | 'charcoal' 52 | ] as const; 53 | -------------------------------------------------------------------------------- /packages/theme/src/utils/createDarkTheme.ts: -------------------------------------------------------------------------------- 1 | import { colorPaletteTokens } from '../alias/darkColorPalette'; 2 | import { generateColorTokens } from '../alias/darkColor'; 3 | 4 | // import { borderRadius, fontSizes, lineHeights, fontFamilies, strokeWidths, fontWeights } from '../global/index'; 5 | import { createShadowTokens } from './shadows'; 6 | import type { BrandVariants, Theme } from '../types'; 7 | // import { durations } from '../global/durations'; 8 | // import { curves } from '../global/curves'; 9 | // import { horizontalSpacings, verticalSpacings } from '../global/spacings'; 10 | 11 | export const createDarkTheme: (brand: BrandVariants) => Theme = brand => { 12 | const colorTokens = generateColorTokens(brand); 13 | 14 | return { 15 | // ...borderRadius, 16 | // ...fontSizes, 17 | // ...lineHeights, 18 | // ...fontFamilies, 19 | // ...fontWeights, 20 | // ...strokeWidths, 21 | // ...horizontalSpacings, 22 | // ...verticalSpacings, 23 | // ...durations, 24 | // ...curves, 25 | 26 | ...colorTokens, 27 | ...colorPaletteTokens, 28 | 29 | ...createShadowTokens(colorTokens.colorNeutralShadowAmbient, colorTokens.colorNeutralShadowKey), 30 | ...createShadowTokens(colorTokens.colorBrandShadowAmbient, colorTokens.colorBrandShadowKey, 'Brand'), 31 | }; 32 | }; 33 | -------------------------------------------------------------------------------- /packages/theme/src/utils/createLightTheme.ts: -------------------------------------------------------------------------------- 1 | import { generateColorTokens } from '../alias/lightColor'; 2 | import { colorPaletteTokens } from '../alias/lightColorPalette'; 3 | import type { BrandVariants, Theme } from '../types'; 4 | // import { borderRadius, fontSizes, lineHeights, fontFamilies, strokeWidths, fontWeights } from '../global/index'; 5 | import { createShadowTokens } from './shadows'; 6 | 7 | // import { durations } from '../global/durations'; 8 | // import { curves } from '../global/curves'; 9 | // import { horizontalSpacings, verticalSpacings } from '../global/spacings'; 10 | 11 | export const createLightTheme: (brand: BrandVariants) => Theme = (brand) => { 12 | const colorTokens = generateColorTokens(brand); 13 | 14 | return { 15 | // ...borderRadius, 16 | // ...fontSizes, 17 | // ...lineHeights, 18 | // ...fontFamilies, 19 | // ...fontWeights, 20 | // ...strokeWidths, 21 | // ...horizontalSpacings, 22 | // ...verticalSpacings, 23 | // ...durations, 24 | // ...curves, 25 | 26 | ...colorTokens, 27 | ...colorPaletteTokens, 28 | 29 | ...createShadowTokens(colorTokens.colorNeutralShadowAmbient, colorTokens.colorNeutralShadowKey), 30 | ...createShadowTokens(colorTokens.colorBrandShadowAmbient, colorTokens.colorBrandShadowKey, 'Brand') 31 | }; 32 | }; 33 | -------------------------------------------------------------------------------- /packages/theme/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { createDarkTheme } from './createDarkTheme'; 2 | export { createLightTheme } from './createLightTheme'; 3 | export { createShadowTokens } from './shadows'; 4 | -------------------------------------------------------------------------------- /packages/theme/src/utils/shadows.ts: -------------------------------------------------------------------------------- 1 | import type { ShadowBrandTokens, ShadowTokens } from '../types'; 2 | 3 | export function createShadowTokens(ambientColor: string, keyColor: string, tokenSuffix: 'Brand'): ShadowBrandTokens; 4 | export function createShadowTokens(ambientColor: string, keyColor: string): ShadowTokens; 5 | 6 | export function createShadowTokens(ambientColor: string, keyColor: string, tokenSuffix: 'Brand' | '' = '') { 7 | return { 8 | [`shadow2${tokenSuffix}`]: `0 0 2px ${ambientColor}, 0 1px 2px ${keyColor}`, 9 | [`shadow4${tokenSuffix}`]: `0 0 2px ${ambientColor}, 0 2px 4px ${keyColor}`, 10 | [`shadow8${tokenSuffix}`]: `0 0 2px ${ambientColor}, 0 4px 8px ${keyColor}`, 11 | [`shadow16${tokenSuffix}`]: `0 0 2px ${ambientColor}, 0 8px 16px ${keyColor}`, 12 | [`shadow28${tokenSuffix}`]: `0 0 8px ${ambientColor}, 0 14px 28px ${keyColor}`, 13 | [`shadow64${tokenSuffix}`]: `0 0 8px ${ambientColor}, 0 32px 64px ${keyColor}` 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /packages/theme/svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' 2 | 3 | /** @type {import('@sveltejs/kit').Config} */ 4 | const config = { 5 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 6 | // for more information about preprocessors 7 | preprocess: vitePreprocess() 8 | }; 9 | 10 | export default config; 11 | -------------------------------------------------------------------------------- /packages/theme/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", // Or another suitable ECMAScript target 4 | "module": "ESNext", // Or your preferred module system (e.g., 'ES2020', 'ESNext') 5 | "declaration": true, // This is the key to generate .d.ts files 6 | "outDir": "./dist", // Optional: Specify the output directory 7 | "rootDir": "./src", // Optional: Specify where your source .ts files live 8 | "moduleResolution": "Bundler" 9 | }, 10 | "include": ["./src/**/*.ts", "src/**/*.js"] // Make sure it includes the path to your TypeScript source files 11 | } 12 | -------------------------------------------------------------------------------- /packages/theme/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import path from 'path' 3 | import pkg from './package.json' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | build:{ 8 | lib:{ 9 | formats:['es'], 10 | entry: './src/index.ts', 11 | name: pkg.name 12 | } 13 | }, 14 | resolve:{ 15 | alias:{ 16 | "@svelte-fui/theme": path.resolve('./src') 17 | } 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /packages/themes/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /packages/themes/.npmignore: -------------------------------------------------------------------------------- 1 | dist/*.stories.svelte 2 | -------------------------------------------------------------------------------- /packages/themes/README.md: -------------------------------------------------------------------------------- 1 | # @svelte-fui/themes 2 | 3 | Svelte FUI Themes offers a comprehensive range of pre-designed, accessible, and customizable UI themes for your Svelte applications. This library boasts the following features: 4 | 5 | - Ready-made stylesheets to expedite your UI development process. 6 | - User-friendly and intuitive interface for seamless integration. 7 | 8 | Supported Themes: 9 | 10 | - [x] Web light 11 | - [x] Web dark 12 | - [ ] Teams light 13 | - [ ] Teams dark 14 | 15 | # Usage 16 | 17 | To begin, install Fluent UI for Svelte. 18 | 19 | ```shell 20 | // pnpm 21 | pnpm install @svelte-fui/themes 22 | 23 | //npm 24 | npm install @svelte-fui/themes 25 | ``` 26 | 27 | Then import the required theme from `@svelte-fui/themes` and passing it as the `theme` prop to the `App` component. For a seamless transition, consider attaching a listener to switch themes based on your system's color scheme. 28 | 29 | Moreover, you can leverage the power of local storage and Svelte store to remember user preferences, ensuring a personalized and consistent experience across sessions. 30 | 31 | ```html 32 | 54 | 55 | 56 | 57 | 58 | ``` 59 | -------------------------------------------------------------------------------- /packages/themes/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@svelte-fui/themes", 3 | "version": "0.1.3", 4 | "description": "", 5 | "type": "module", 6 | "sideEffects": false, 7 | "scripts": { 8 | "build": "npx tsc", 9 | "prepublish": "pnpm run build" 10 | }, 11 | "author": "", 12 | "license": "MIT", 13 | "files": [ 14 | "dist" 15 | ], 16 | "devDependencies": { 17 | "@sveltejs/package": "^2.0.2", 18 | "@sveltejs/vite-plugin-svelte": "^2.0.3", 19 | "@tsconfig/svelte": "^4.0.1", 20 | "lodash-es": "^4.17.21", 21 | "svelte": "^4.0.0", 22 | "svelte-check": "^2.10.3", 23 | "tslib": "^2.5.0", 24 | "typescript": "^5.0.2", 25 | "vite": "^5.1.0" 26 | }, 27 | "dependencies": { 28 | "@svelte-fui/theme": "^0.1.0" 29 | }, 30 | "peerDependencies": { 31 | "@svelte-fui/theme": "^0.1.0" 32 | }, 33 | "exports": { 34 | ".": { 35 | "types": "./dist/index.d.ts", 36 | "svelte": "./dist/index.js", 37 | "default": "./dist/index.js" 38 | }, 39 | "./web": { 40 | "types": "./dist/web/index.d.ts", 41 | "svelte": "./dist/web/index.js", 42 | "default": "./dist/web/index.js" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/themes/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './web' 2 | -------------------------------------------------------------------------------- /packages/themes/src/web/dark.ts: -------------------------------------------------------------------------------- 1 | import { brandWeb } from '@svelte-fui/theme/global/brandColors'; 2 | import type { Theme } from '@svelte-fui/theme/types'; 3 | import { createDarkTheme } from '@svelte-fui/theme/utils'; 4 | 5 | export const webDarkTheme = createDarkTheme(brandWeb) satisfies Theme; 6 | -------------------------------------------------------------------------------- /packages/themes/src/web/index.ts: -------------------------------------------------------------------------------- 1 | export * from './light' 2 | export * from './dark' 3 | -------------------------------------------------------------------------------- /packages/themes/src/web/light.ts: -------------------------------------------------------------------------------- 1 | import { brandWeb } from '@svelte-fui/theme/global/brandColors'; 2 | import type { Theme } from '@svelte-fui/theme/types'; 3 | import { createLightTheme } from '@svelte-fui/theme/utils'; 4 | 5 | export const webLightTheme = createLightTheme(brandWeb) satisfies Theme; 6 | -------------------------------------------------------------------------------- /packages/themes/svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' 2 | 3 | /** @type {import('@sveltejs/kit').Config} */ 4 | const config = { 5 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 6 | // for more information about preprocessors 7 | preprocess: vitePreprocess() 8 | }; 9 | 10 | export default config; 11 | -------------------------------------------------------------------------------- /packages/themes/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", // Or another suitable ECMAScript target 4 | "module": "ESNext", // Or your preferred module system (e.g., 'ES2020', 'ESNext') 5 | "declaration": true, // This is the key to generate .d.ts files 6 | "outDir": "./dist", // Optional: Specify the output directory 7 | "rootDir": "./src", // Optional: Specify where your source .ts files live 8 | "moduleResolution": "Bundler" 9 | }, 10 | "include": ["./src/**/*.ts", "src/**/*.js"] // Make sure it includes the path to your TypeScript source files 11 | } 12 | -------------------------------------------------------------------------------- /packages/themes/vite.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { defineConfig } from 'vite'; 3 | import pkg from './package.json'; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | build: { 8 | lib: { 9 | formats: ['es'], 10 | entry: { 11 | index: './src/index.ts', 12 | web: './src/web/index.ts' 13 | }, 14 | name: pkg.name 15 | } 16 | }, 17 | resolve: { 18 | alias: { 19 | '@svelte-fui/theme': path.resolve('../theme/src') 20 | } 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | import type { PlaywrightTestConfig } from '@playwright/test'; 2 | 3 | const config: PlaywrightTestConfig = { 4 | webServer: { 5 | command: 'npm run build && npm run preview', 6 | port: 4173 7 | }, 8 | testDir: 'tests' 9 | }; 10 | 11 | export default config; 12 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/**" 3 | - "app/**" 4 | - "packages/**" 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | /** 5 | Svelte Preprocess cannot figure out whether you have a value or a type, so tell TypeScript 6 | to enforce using `import type` instead of `import` for Types. 7 | */ 8 | "verbatimModuleSyntax": true, 9 | /** 10 | To have warnings/errors of the Svelte compiler at the correct position, 11 | enable source maps by default. 12 | */ 13 | "sourceMap": true, 14 | "strict": false, 15 | "esModuleInterop": true, 16 | "skipLibCheck": true, 17 | "forceConsistentCasingInFileNames": true, 18 | "target": "ESNext", 19 | "useDefineForClassFields": true, 20 | "module": "ESNext", 21 | "resolveJsonModule": true, 22 | /** 23 | * Typecheck JS in `.svelte` and `.js` files by default. 24 | * Disable checkJs if you'd like to use dynamic types in JS. 25 | * Note that setting allowJs false does not prevent the use 26 | * of JS in `.svelte` files. 27 | */ 28 | "allowJs": true, 29 | "checkJs": true, 30 | "isolatedModules": true, 31 | "moduleResolution": "bundler", 32 | "composite": true 33 | }, 34 | "include": [ 35 | "./packages/*" 36 | ], 37 | "exclude": [ 38 | "./node_modules" 39 | ], 40 | "references": [ 41 | { 42 | "path": "./tsconfig.node.json" 43 | } 44 | ] 45 | } 46 | --------------------------------------------------------------------------------