├── cli.cjs ├── .github └── workflows │ └── publish.yaml ├── packages ├── theme │ ├── src │ │ ├── alias │ │ │ ├── index.ts │ │ │ └── lightColorPalette.ts │ │ ├── global │ │ │ ├── curves.ts │ │ │ ├── strokeWidth.ts │ │ │ ├── index.ts │ │ │ ├── duration.ts │ │ │ ├── spacings.ts │ │ │ ├── timingFunctions.ts │ │ │ ├── shadow.ts │ │ │ ├── fonts.ts │ │ │ ├── colorPalette.ts │ │ │ └── brandColors.ts │ │ ├── index.ts │ │ ├── utils │ │ │ ├── index.ts │ │ │ ├── shadows.ts │ │ │ ├── createLightTheme.ts │ │ │ └── createDarkTheme.ts │ │ └── sharedColorNames.ts │ ├── .gitignore │ ├── .npmignore │ ├── svelte.config.js │ ├── vite.config.ts │ ├── README.md │ ├── tsconfig.json │ └── package.json ├── core │ ├── src │ │ ├── lib │ │ │ ├── tokens │ │ │ │ └── index.ts │ │ │ ├── utils │ │ │ │ ├── index.ts │ │ │ │ └── context.ts │ │ │ ├── layout │ │ │ │ ├── context.ts │ │ │ │ ├── layout.stories.svelte │ │ │ │ ├── index.ts │ │ │ │ └── layout.svelte │ │ │ ├── context │ │ │ │ ├── index.ts │ │ │ │ └── sharedContext.ts │ │ │ ├── icon │ │ │ │ ├── index.ts │ │ │ │ ├── icon.svelte │ │ │ │ └── icon.stories.svelte │ │ │ ├── link │ │ │ │ ├── index.ts │ │ │ │ ├── link.stories.svelte │ │ │ │ └── Link.svelte │ │ │ ├── text │ │ │ │ ├── index.ts │ │ │ │ ├── text.stories.svelte │ │ │ │ └── text.svelte │ │ │ ├── avatar │ │ │ │ ├── index.ts │ │ │ │ └── avatar.stories.svelte │ │ │ ├── slider │ │ │ │ ├── index.ts │ │ │ │ └── slider.stories.svelte │ │ │ ├── tailwindcss │ │ │ │ ├── index.ts │ │ │ │ ├── utils │ │ │ │ │ └── index.ts │ │ │ │ └── colors_shared.js │ │ │ ├── divider │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── divider.stories.svelte │ │ │ ├── spinner │ │ │ │ ├── index.ts │ │ │ │ ├── spinner.stories.svelte │ │ │ │ └── spinner-default-icon.svelte │ │ │ ├── switch │ │ │ │ ├── index.ts │ │ │ │ └── switch.stories.svelte │ │ │ ├── tooltip │ │ │ │ ├── index.ts │ │ │ │ └── tooltip.stories.svelte │ │ │ ├── checkbox │ │ │ │ ├── index.ts │ │ │ │ └── checkbox.stories.svelte │ │ │ ├── radio │ │ │ │ ├── types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── context.ts │ │ │ │ ├── radio-group.svelte │ │ │ │ ├── radio.stories.svelte │ │ │ │ └── radio-group.stories.svelte │ │ │ ├── table │ │ │ │ ├── tr │ │ │ │ │ ├── index.ts │ │ │ │ │ └── context.ts │ │ │ │ ├── type.ts │ │ │ │ ├── index.ts │ │ │ │ ├── td.svelte │ │ │ │ ├── store.ts │ │ │ │ ├── table-root.svelte │ │ │ │ ├── context.ts │ │ │ │ ├── th.svelte │ │ │ │ └── td-selection.svelte │ │ │ ├── button │ │ │ │ ├── index.ts │ │ │ │ ├── compound-button │ │ │ │ │ ├── compound-button-body.svelte │ │ │ │ │ ├── compound-button-secondary-content.svelte │ │ │ │ │ ├── index.ts │ │ │ │ │ └── compound-button.stories.svelte │ │ │ │ ├── menu-button │ │ │ │ │ ├── menu-button-menu.svelte │ │ │ │ │ ├── menu-button-root.svelte │ │ │ │ │ ├── menu-button-item.svelte │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── menu-button-button.svelte │ │ │ │ │ └── menu-button.stories.svelte │ │ │ │ ├── types.ts │ │ │ │ └── button.stories.svelte │ │ │ ├── field │ │ │ │ ├── types,.ts │ │ │ │ ├── field-message-info.svelte │ │ │ │ ├── field-message-error.svelte │ │ │ │ ├── field-message-warning.svelte │ │ │ │ ├── field-message-success.svelte │ │ │ │ ├── index.ts │ │ │ │ ├── context.ts │ │ │ │ ├── field-message.svelte │ │ │ │ ├── field.svelte │ │ │ │ └── field.stories.svelte │ │ │ ├── label │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ ├── label.svelte │ │ │ │ └── label.stories.svelte │ │ │ ├── combobox │ │ │ │ ├── types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── context.ts │ │ │ │ ├── combobox-trigger.svelte │ │ │ │ ├── combobox.stories.svelte │ │ │ │ ├── combobox-menu.svelte │ │ │ │ └── combobox-root.svelte │ │ │ ├── popover │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ ├── context.ts │ │ │ │ ├── popover.stories.svelte │ │ │ │ └── popover.svelte │ │ │ ├── internal │ │ │ │ ├── transition.ts │ │ │ │ ├── utils.ts │ │ │ │ └── context.ts │ │ │ ├── app │ │ │ │ ├── index.ts │ │ │ │ ├── utils.ts │ │ │ │ ├── root-backdrop-layer.svelte │ │ │ │ ├── backdrop-context.ts │ │ │ │ ├── root-context.ts │ │ │ │ └── root.svelte │ │ │ ├── styles │ │ │ │ └── root.css │ │ │ ├── dialog │ │ │ │ ├── types.ts │ │ │ │ ├── dialog-body.svelte │ │ │ │ ├── dialog-header.svelte │ │ │ │ ├── index.ts │ │ │ │ └── dialog-actions.svelte │ │ │ ├── icons │ │ │ │ ├── checkmark-filled.svelte │ │ │ │ ├── chevron-down-regular.svelte │ │ │ │ ├── chevron-right.svelte │ │ │ │ ├── arrow-up-regular.svelte │ │ │ │ ├── checkmark-circle-filled.svelte │ │ │ │ ├── add-regular.svelte │ │ │ │ ├── error-circle-filled.svelte │ │ │ │ ├── warning-filled.svelte │ │ │ │ ├── info-filled.svelte │ │ │ │ ├── alert-regular.svelte │ │ │ │ └── person-regular.svelte │ │ │ ├── card │ │ │ │ ├── index.ts │ │ │ │ ├── card-footer.svelte │ │ │ │ ├── card-preview.svelte │ │ │ │ ├── context.ts │ │ │ │ ├── card-header.svelte │ │ │ │ └── card-header.stories.svelte │ │ │ ├── input │ │ │ │ ├── types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── context.ts │ │ │ │ ├── input.svelte │ │ │ │ ├── input-element.svelte │ │ │ │ └── input.stories.svelte │ │ │ ├── actions │ │ │ │ ├── animation.ts │ │ │ │ ├── portal.ts │ │ │ │ └── dom.ts │ │ │ ├── accordion │ │ │ │ ├── index.ts │ │ │ │ ├── accordion-panel.svelte │ │ │ │ ├── accordion-root.svelte │ │ │ │ ├── context.ts │ │ │ │ └── accordion-item.svelte │ │ │ ├── menu │ │ │ │ ├── menu-divider.svelte │ │ │ │ ├── menu-group.svelte │ │ │ │ ├── index.ts │ │ │ │ ├── menu-trigger.svelte │ │ │ │ ├── types.ts │ │ │ │ ├── context-item.ts │ │ │ │ ├── context-root.ts │ │ │ │ └── menu-item.svelte │ │ │ ├── dropdown │ │ │ │ ├── types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── context.ts │ │ │ │ ├── dropdown-arrow.svelte │ │ │ │ ├── dropdown-trigger.svelte │ │ │ │ ├── dropdown-root.svelte │ │ │ │ ├── dropdown-item.svelte │ │ │ │ └── dropdown.stories.svelte │ │ │ └── index.ts │ │ ├── index.test.ts │ │ ├── routes │ │ │ └── +page.svelte │ │ ├── app.d.ts │ │ └── app.html │ ├── .npmrc │ ├── tsconfig.tsbuildinfo │ ├── .storybook │ │ ├── preview-head.html │ │ ├── manager.ts │ │ ├── global.css │ │ ├── preview.ts │ │ └── main.ts │ ├── .prettierignore │ ├── static │ │ └── favicon.png │ ├── tests │ │ └── test.ts │ ├── .prettierrc │ ├── postcss.config.js │ ├── tailwind.config.js │ ├── playwright.config.ts │ ├── .gitignore │ ├── vite.config.ts │ ├── tsconfig.json │ ├── eslint.config.js │ ├── svelte.config.js │ └── README.md ├── themes │ ├── .gitignore │ ├── .npmignore │ ├── src │ │ ├── index.ts │ │ └── web │ │ │ ├── index.ts │ │ │ ├── dark.ts │ │ │ └── light.ts │ ├── svelte.config.js │ ├── vite.config.ts │ ├── tsconfig.json │ ├── package.json │ └── README.md └── tailwindcss │ ├── .gitignore │ ├── src │ ├── index.ts │ ├── utils │ │ └── index.ts │ └── colors_shared.ts │ ├── vite.config.ts │ ├── tsconfig.json │ ├── package.json │ └── README.md ├── .npmrc ├── pnpm-workspace.yaml ├── .gitignore ├── .eslintignore ├── .prettierignore ├── playwright.config.ts ├── .eslintrc.cjs ├── .prettierrc ├── LICENSE ├── tsconfig.json └── package.json /cli.cjs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/theme/src/alias/index.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/src/lib/tokens/index.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/src/lib/utils/index.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/theme/src/global/curves.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/layout/context.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/theme/src/global/strokeWidth.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/theme/src/global/index.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | node-linker=hoisted 3 | -------------------------------------------------------------------------------- /packages/core/src/lib/layout/layout.stories.svelte: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"version":"5.0.4"} -------------------------------------------------------------------------------- /packages/theme/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /packages/theme/.npmignore: -------------------------------------------------------------------------------- 1 | dist/*.stories.svelte 2 | -------------------------------------------------------------------------------- /packages/themes/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /packages/themes/.npmignore: -------------------------------------------------------------------------------- 1 | dist/*.stories.svelte 2 | -------------------------------------------------------------------------------- /packages/tailwindcss/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /packages/themes/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './web' 2 | -------------------------------------------------------------------------------- /packages/theme/src/index.ts: -------------------------------------------------------------------------------- 1 | export type * from './types' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/context/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sharedContext' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/icon/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Icon} from './icon.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/link/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Link} from './Link.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/text/index.ts: -------------------------------------------------------------------------------- 1 | export {default as Text} from './text.svelte' 2 | -------------------------------------------------------------------------------- /packages/themes/src/web/index.ts: -------------------------------------------------------------------------------- 1 | export * from './light' 2 | export * from './dark' 3 | -------------------------------------------------------------------------------- /packages/core/src/lib/avatar/index.ts: -------------------------------------------------------------------------------- 1 | export {default as Avatar } from './avatar.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/slider/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Slider } from './slider.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/tailwindcss/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './tailwind.config'; 2 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/**" 3 | - "app/**" 4 | - "packages/**" 5 | -------------------------------------------------------------------------------- /packages/core/.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/core/src/lib/divider/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Divider } from './divider.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/layout/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Layout } from './layout.svelte'; 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/spinner/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Spinner } from './spinner.svelte'; 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/switch/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Switch } from './switch.svelte'; 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tooltip } from './tooltip.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/checkbox/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Checkbox } from './checkbox.svelte' 2 | -------------------------------------------------------------------------------- /packages/core/.prettierignore: -------------------------------------------------------------------------------- 1 | # Package Managers 2 | package-lock.json 3 | pnpm-lock.yaml 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /packages/core/src/lib/radio/types.ts: -------------------------------------------------------------------------------- 1 | export type Layout = 'vertical' | 'horizontal' | 'stacked-horizontal' 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/table/tr/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tr} from './tr.svelte' 2 | export * from './context' 3 | -------------------------------------------------------------------------------- /packages/core/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu-man/svelte-fui/HEAD/packages/core/static/favicon.png -------------------------------------------------------------------------------- /packages/core/src/lib/button/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Button } from './button.svelte'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/types,.ts: -------------------------------------------------------------------------------- 1 | export type FieldState = 'none' | 'error' | 'warning' | 'success' | undefined; 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/label/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Label } from './label.svelte'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /packages/core/src/lib/combobox/types.ts: -------------------------------------------------------------------------------- 1 | export type ComboboxTriggerProps = { 2 | class?: string; 3 | placeholder?: string; 4 | }; 5 | -------------------------------------------------------------------------------- /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/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/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/theme/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { createDarkTheme } from './createDarkTheme'; 2 | export { createLightTheme } from './createLightTheme'; 3 | export { createShadowTokens } from './shadows'; 4 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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/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/.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/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/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/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/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/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/src/lib/icons/checkmark-filled.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/button/compound-button/compound-button-body.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /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/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/core/src/lib/icons/chevron-down-regular.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/chevron-right.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /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/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/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/dialog/dialog-body.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 10 |
11 | -------------------------------------------------------------------------------- /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/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/lib/icons/arrow-up-regular.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/checkmark-circle-filled.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /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/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/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/core/src/lib/dialog/dialog-header.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /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/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/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/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/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/icons/add-regular.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /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/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/core/src/lib/button/menu-button/menu-button-item.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /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/core/src/lib/field/field-message-info.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/error-circle-filled.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /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/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/field/field-message-error.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/warning-filled.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/menu/menu-divider.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /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/src/lib/card/card-footer.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | 11 |
12 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /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/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/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/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/menu/menu-group.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 | 13 |
14 | -------------------------------------------------------------------------------- /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/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/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/core/src/lib/icons/info-filled.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/field-message-warning.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /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/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/dialog/dialog-actions.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
14 | 15 |
16 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/field-message-success.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /packages/core/src/lib/icons/alert-regular.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /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/core/src/lib/menu/menu-trigger.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | -------------------------------------------------------------------------------- /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/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/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/core/src/lib/button/menu-button/menu-button-button.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/core/src/lib/icons/person-regular.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /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/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/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/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/accordion/accordion-panel.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | {#if $active$} 13 | 14 |
15 | 16 |
17 | {/if} 18 | 19 | 24 | -------------------------------------------------------------------------------- /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/core/src/lib/app/root-backdrop-layer.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 |
16 | 17 | -------------------------------------------------------------------------------- /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/icon/icon.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 | 13 |
14 | 15 | 24 | -------------------------------------------------------------------------------- /packages/core/src/lib/layout/layout.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 |
25 | 26 |
27 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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/card/card-preview.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |
13 | 14 | 15 |
16 | 17 | 36 | -------------------------------------------------------------------------------- /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/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/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/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/table/td.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 | 33 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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/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/icon/icon.stories.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 |
29 |
30 |
31 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/core/src/lib/dropdown/dropdown-trigger.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 | 35 | 36 | 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 | -------------------------------------------------------------------------------- /packages/core/src/lib/accordion/accordion-root.svelte: -------------------------------------------------------------------------------- 1 | 33 | 34 |
35 | 36 |
37 | 38 | 40 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/core/src/lib/radio/radio-group.svelte: -------------------------------------------------------------------------------- 1 | 35 | 36 |
37 | 38 |
39 | 40 | 49 | -------------------------------------------------------------------------------- /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/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/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/spinner/spinner.stories.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 41 | 42 |
43 | Loding Data... 44 |
45 |
46 |
47 | -------------------------------------------------------------------------------- /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/table/table-root.svelte: -------------------------------------------------------------------------------- 1 | 34 | 35 | 36 | 37 |
38 | 39 | 52 | -------------------------------------------------------------------------------- /packages/core/src/lib/avatar/avatar.stories.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 | 40 | 41 | 42 | 43 |
44 | 45 |
46 |
47 |
48 | -------------------------------------------------------------------------------- /packages/core/src/lib/checkbox/checkbox.stories.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 41 | 42 |
43 | 44 | 48 |
49 |
50 |
51 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/src/lib/card/card-header.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | 22 | 23 |
24 | 25 | 66 | -------------------------------------------------------------------------------- /packages/core/src/lib/spinner/spinner-default-icon.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 73 | -------------------------------------------------------------------------------- /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/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/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/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/label/label.svelte: -------------------------------------------------------------------------------- 1 | 31 | 32 | 48 | 49 | 74 | -------------------------------------------------------------------------------- /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/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/label/label.stories.svelte: -------------------------------------------------------------------------------- 1 | 55 | 56 | 75 | 76 | 77 | 78 |
79 | 80 |
81 |
82 |
83 | -------------------------------------------------------------------------------- /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/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/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/popover/popover.stories.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 28 | 29 | 30 | 31 | 57 | 58 | 59 |
60 |
Hello World!
61 |
62 |
63 |
64 |
65 | -------------------------------------------------------------------------------- /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/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/dropdown/dropdown-root.svelte: -------------------------------------------------------------------------------- 1 | 68 | 69 |
70 | 71 | 72 | 73 |
74 | -------------------------------------------------------------------------------- /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/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/combobox/combobox-menu.svelte: -------------------------------------------------------------------------------- 1 | 59 | 60 | 61 |
74 | 75 |
76 |
77 | -------------------------------------------------------------------------------- /packages/core/src/lib/link/Link.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 29 | 30 | 31 | 32 | 100 | -------------------------------------------------------------------------------- /packages/core/src/lib/accordion/accordion-item.svelte: -------------------------------------------------------------------------------- 1 | 84 | 85 |
86 | 87 |
88 | 89 | 93 | -------------------------------------------------------------------------------- /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/input/input-element.svelte: -------------------------------------------------------------------------------- 1 | 60 | 61 | 86 | -------------------------------------------------------------------------------- /packages/core/src/lib/combobox/combobox-root.svelte: -------------------------------------------------------------------------------- 1 | 76 | 77 |
{}}> 78 | 88 | 89 |
90 | -------------------------------------------------------------------------------- /packages/core/src/lib/dropdown/dropdown-item.svelte: -------------------------------------------------------------------------------- 1 | 55 | 56 | 71 | 72 | 86 | -------------------------------------------------------------------------------- /packages/core/src/lib/field/field.svelte: -------------------------------------------------------------------------------- 1 | 60 | 61 |
62 | 63 | 64 |
65 | 66 | 99 | -------------------------------------------------------------------------------- /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/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/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/text/text.svelte: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | 100 | -------------------------------------------------------------------------------- /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/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/src/lib/menu/menu-item.svelte: -------------------------------------------------------------------------------- 1 | 82 | 83 | 95 | 96 | 107 | -------------------------------------------------------------------------------- /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/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/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/td-selection.svelte: -------------------------------------------------------------------------------- 1 | 59 | 60 | 67 | 68 | 107 | -------------------------------------------------------------------------------- /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/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/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/theme/src/alias/lightColorPalette.ts: -------------------------------------------------------------------------------- 1 | /* color palette used in both darkTheme and teamsDarkTheme */ 2 | import { upperFirst } from 'lodash-es'; 3 | import { personaSharedColors, statusSharedColors } from '../global/colorPalette'; 4 | import { personaSharedColorNames, statusSharedColorNames } from '../sharedColorNames'; 5 | import type { 6 | ColorPaletteTokens, 7 | PersonaColorPaletteTokens, 8 | PersonaSharedColors, 9 | StatusColorPaletteTokens, 10 | StatusSharedColors 11 | } from '../types'; 12 | 13 | const statusColorPaletteTokens = applyStatusColorPalettePatches( 14 | statusSharedColorNames.reduce((acc, sharedColor) => { 15 | const upperedFirstColorName = upperFirst(sharedColor); 16 | 17 | const sharedColorTokens = { 18 | [`colorPalette${upperedFirstColorName}Background1`]: statusSharedColors[sharedColor].tint60, 19 | [`colorPalette${upperedFirstColorName}Background2`]: statusSharedColors[sharedColor].tint40, 20 | [`colorPalette${upperedFirstColorName}Background3`]: statusSharedColors[sharedColor].primary, 21 | [`colorPalette${upperedFirstColorName}Foreground1`]: statusSharedColors[sharedColor].shade10, 22 | [`colorPalette${upperedFirstColorName}Foreground2`]: statusSharedColors[sharedColor].shade30, 23 | [`colorPalette${upperedFirstColorName}Foreground3`]: statusSharedColors[sharedColor].primary, 24 | [`colorPalette${upperedFirstColorName}BorderActive`]: statusSharedColors[sharedColor].primary, 25 | [`colorPalette${upperedFirstColorName}Border1`]: statusSharedColors[sharedColor].tint40, 26 | [`colorPalette${upperedFirstColorName}Border2`]: statusSharedColors[sharedColor].primary 27 | }; 28 | 29 | return Object.assign(acc, sharedColorTokens); 30 | }, {} as StatusColorPaletteTokens), 31 | statusSharedColors 32 | ); 33 | 34 | const personaColorPaletteTokens = applyPersonaColorPalettePatches( 35 | personaSharedColorNames.reduce((acc, sharedColor) => { 36 | const upperedFirstColorName = upperFirst(sharedColor); 37 | 38 | const sharedColorTokens = { 39 | [`colorPalette${upperedFirstColorName}Background2`]: personaSharedColors[sharedColor].tint40, 40 | [`colorPalette${upperedFirstColorName}Foreground2`]: personaSharedColors[sharedColor].shade30, 41 | [`colorPalette${upperedFirstColorName}BorderActive`]: personaSharedColors[sharedColor].primary 42 | }; 43 | 44 | return Object.assign(acc, sharedColorTokens); 45 | }, {} as PersonaColorPaletteTokens), 46 | personaSharedColors 47 | ); 48 | 49 | export const colorPaletteTokens: ColorPaletteTokens = { ...statusColorPaletteTokens, ...personaColorPaletteTokens }; 50 | 51 | function applyStatusColorPalettePatches(tokens: StatusColorPaletteTokens, shared: StatusSharedColors) { 52 | // one-off patch for yellow 53 | tokens.colorPaletteYellowForeground1 = shared.yellow.shade30; 54 | 55 | tokens.colorPaletteRedForegroundInverted = shared.red.tint20; 56 | tokens.colorPaletteGreenForegroundInverted = shared.green.tint20; 57 | tokens.colorPaletteYellowForegroundInverted = shared.yellow.tint40; 58 | 59 | return tokens; 60 | } 61 | 62 | function applyPersonaColorPalettePatches(tokens: PersonaColorPaletteTokens, shared: PersonaSharedColors) { 63 | // one-off patches 64 | // No patches 65 | 66 | return tokens; 67 | } 68 | --------------------------------------------------------------------------------