├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierrc ├── eslint.config.mjs ├── license.txt ├── locales ├── index.js ├── locales │ ├── cn.js │ ├── de.js │ ├── en.js │ ├── es.js │ ├── fr.js │ ├── it.js │ ├── ja.js │ ├── pt.js │ └── ru.js └── package.json ├── package.json ├── readme.md ├── site ├── index.html ├── index.js ├── package.json ├── public │ └── assets │ │ ├── avatars │ │ ├── avatar01.png │ │ ├── avatar04.png │ │ ├── avatar05.png │ │ ├── avatar06.png │ │ ├── avatar07.png │ │ ├── avatar09.png │ │ └── avatar10.png │ │ └── icons │ │ ├── Willow.svg │ │ └── Willow_dark.svg ├── src │ ├── CustomCoreWidgets.svelte │ ├── Demo.svelte │ ├── Main.svelte │ ├── ThemeSelect.svelte │ ├── components │ │ ├── CalendarUploader.svelte │ │ ├── CustomThemeSelect.svelte │ │ ├── Form.svelte │ │ ├── Icons │ │ │ └── LockIcon.svelte │ │ ├── RadioCheckboxes.svelte │ │ ├── SearchList.svelte │ │ └── Topbar.svelte │ └── data │ │ └── index.js ├── svelte.config.js └── vite.config.js ├── svelte ├── .gitignore ├── cypress.config.js ├── cypress │ ├── e2e │ │ └── demos.cy.js │ ├── fixtures │ │ └── example.json │ └── support │ │ ├── commands.js │ │ └── e2e.js ├── demos │ ├── cases │ │ ├── Area.svelte │ │ ├── Basic.svelte │ │ ├── Buttons.svelte │ │ ├── Calendar.svelte │ │ ├── Checkbox.svelte │ │ ├── ColorPicker.svelte │ │ ├── ColorSelect.svelte │ │ ├── Combo.svelte │ │ ├── Counter.svelte │ │ ├── DatePicker.svelte │ │ ├── DateRangePicker.svelte │ │ ├── Field.svelte │ │ ├── Icon.svelte │ │ ├── Locales.svelte │ │ ├── Messages.svelte │ │ ├── ModalArea.svelte │ │ ├── Month.svelte │ │ ├── MultiCombo.svelte │ │ ├── Pager.svelte │ │ ├── Popup.svelte │ │ ├── Radio.svelte │ │ ├── RangeCalendar.svelte │ │ ├── RichSelect.svelte │ │ ├── Segmented.svelte │ │ ├── Select.svelte │ │ ├── SideArea.svelte │ │ ├── Slider.svelte │ │ ├── Switch.svelte │ │ ├── Tabs.svelte │ │ ├── Text.svelte │ │ ├── TextArea.svelte │ │ ├── TimePicker.svelte │ │ ├── Timepicker.svelte │ │ └── TwoState.svelte │ ├── common │ │ ├── Index.svelte │ │ ├── Link.svelte │ │ ├── Router.svelte │ │ └── helpers.js │ ├── custom │ │ └── UserOption.svelte │ ├── data │ │ ├── icons.js │ │ ├── roles.js │ │ └── userlist.js │ ├── index.js │ └── routes.js ├── index.html ├── license.txt ├── package.json ├── postcss.config.js ├── readme.md ├── src │ ├── Locale.svelte │ ├── components │ │ ├── Area.svelte │ │ ├── Button.svelte │ │ ├── Calendar.svelte │ │ ├── Checkbox.svelte │ │ ├── CheckboxGroup.svelte │ │ ├── ColorBoard.svelte │ │ ├── ColorPicker.svelte │ │ ├── ColorSelect.svelte │ │ ├── Combo.svelte │ │ ├── Counter.svelte │ │ ├── DatePicker.svelte │ │ ├── DateRangePicker.svelte │ │ ├── Dropdown.svelte │ │ ├── Field.svelte │ │ ├── Globals.svelte │ │ ├── Icon.svelte │ │ ├── Modal.svelte │ │ ├── ModalArea.svelte │ │ ├── MultiCombo.svelte │ │ ├── Notice.svelte │ │ ├── Notices.svelte │ │ ├── Pager.svelte │ │ ├── Popup.svelte │ │ ├── Portal.svelte │ │ ├── RadioButton.svelte │ │ ├── RadioButtonGroup.svelte │ │ ├── RangeCalendar.svelte │ │ ├── RichSelect.svelte │ │ ├── Segmented.svelte │ │ ├── Select.svelte │ │ ├── SideArea.svelte │ │ ├── Slider.svelte │ │ ├── Switch.svelte │ │ ├── Tabs.svelte │ │ ├── Text.svelte │ │ ├── TextArea.svelte │ │ ├── TimePicker.svelte │ │ ├── Timepicker.svelte │ │ ├── TwoState.svelte │ │ ├── calendar │ │ │ ├── Button.svelte │ │ │ ├── Duodecade.svelte │ │ │ ├── Header.svelte │ │ │ ├── Month.svelte │ │ │ ├── Panel.svelte │ │ │ ├── Year.svelte │ │ │ └── helpers.js │ │ ├── helpers.js │ │ └── helpers │ │ │ ├── SuggestDropdown.svelte │ │ │ ├── colorTransformator.js │ │ │ ├── colorValidation.js │ │ │ ├── listnav.js │ │ │ └── sliderMove.js │ ├── index.js │ └── themes │ │ ├── FontOpenSans.svelte │ │ ├── FonttRoboto.svelte │ │ ├── Material.svelte │ │ ├── Willow.svelte │ │ └── WillowDark.svelte ├── svelte.config.js ├── tests │ ├── Index.svelte │ ├── index.html │ ├── index.js │ └── routes.js ├── vite.config.js └── whatsnew.md └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true, 6 | es6: true, 7 | }, 8 | extends: ["plugin:cypress/recommended", "eslint:recommended", "prettier"], 9 | parserOptions: { 10 | ecmaVersion: 2020, 11 | sourceType: "module", 12 | extraFileExtensions: [".svelte"], 13 | }, 14 | plugins: ["svelte3"], 15 | 16 | overrides: [ 17 | { 18 | files: ["*.svelte"], 19 | processor: "svelte3/svelte3", 20 | }, 21 | ], 22 | settings: { 23 | // [todo] we can add stylelint for this 24 | "svelte3/ignore-styles": () => true, 25 | }, 26 | rules: { 27 | "no-bitwise": ["error"], 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | 4 | *.zip 5 | .Ds_store 6 | *.tgz 7 | *.log 8 | .vscode 9 | .idea 10 | .env.local -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | yarn run lint-staged 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "semi": true, 4 | "singleQuote": false, 5 | "quoteProps": "as-needed", 6 | "trailingComma": "es5", 7 | "bracketSpacing": true, 8 | "arrowParens": "avoid", 9 | "svelteSortOrder": "options-scripts-markup-styles", 10 | "plugins": [ 11 | "prettier-plugin-svelte" 12 | ], 13 | "overrides": [ 14 | { 15 | "files": "*.svelte", 16 | "options": { 17 | "parser": "svelte" 18 | } 19 | }, 20 | { 21 | "files": "*.ts", 22 | "options": { 23 | "parser": "typescript" 24 | } 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import eslintConfigPrettier from "eslint-config-prettier"; 2 | import eslintPluginSvelte from 'eslint-plugin-svelte'; 3 | import * as svelteParser from 'svelte-eslint-parser'; 4 | import tsLint from "typescript-eslint"; 5 | import jsLint from "@eslint/js"; 6 | import vitest from "eslint-plugin-vitest"; 7 | import globals from "globals"; 8 | 9 | export default [{ 10 | ignores: ["node_modules/", "dist/", "build/", "coverage/", "public/", "svelte/vite.config.js"], 11 | }, 12 | jsLint.configs.recommended, 13 | ...tsLint.configs.recommended, 14 | ...eslintPluginSvelte.configs['flat/recommended'], 15 | eslintConfigPrettier, 16 | vitest.configs.recommended, 17 | ...eslintPluginSvelte.configs["flat/prettier"], 18 | { 19 | rules: { 20 | "no-bitwise": ["error"], 21 | // there is a misconception between esLint and svelte compiler 22 | // rules that are necessary for compiler, throw errors in esLint 23 | // need to be revised with next version of toolchain 24 | "svelte/no-unused-svelte-ignore": "off", 25 | "svelte/valid-compile": "off", 26 | // Ignore unused vars starting with _ 27 | // "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], 28 | // // Turn off the need for explicit function return types 29 | // "@typescript-eslint/explicit-function-return-type": "off", 30 | // // Warn when "any" type is used 31 | "@typescript-eslint/no-explicit-any": "off", 32 | // // Warn on @ts-ignore comments 33 | // "@typescript-eslint/ban-ts-comment": "warn", 34 | // // Public methods should have return types 35 | // "@typescript-eslint/explicit-module-boundary-types": "error", 36 | }, 37 | }, 38 | { 39 | languageOptions: { 40 | globals: { ...globals.browser, ...globals.es2022 }, 41 | ecmaVersion: 2022, 42 | sourceType: "module", 43 | parserOptions: { 44 | extraFileExtensions: [".svelte"], 45 | warnOnUnsupportedTypeScriptVersion: false, 46 | tsconfigRootDir: import.meta.dirname, 47 | }, 48 | }, 49 | 50 | }, 51 | { 52 | 53 | files: ["**/*.svelte"], 54 | rules: { 55 | "@typescript-eslint/no-unused-expressions": "off" 56 | } 57 | }, 58 | { 59 | // temporarily ignore cypress folder 60 | ignores: [ 61 | "**/cypress/" 62 | ] 63 | }, 64 | { 65 | 66 | files: ["**/*.svelte.js"], 67 | languageOptions: { 68 | parser: svelteParser, 69 | } 70 | } 71 | ]; 72 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 XB Software Sp. z o.o. 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. -------------------------------------------------------------------------------- /locales/index.js: -------------------------------------------------------------------------------- 1 | export { default as en } from "./locales/en.js"; 2 | export { default as cn } from "./locales/cn.js"; 3 | export { default as de } from "./locales/de.js"; 4 | export { default as es } from "./locales/es.js"; 5 | export { default as fr } from "./locales/fr.js"; 6 | export { default as it } from "./locales/it.js"; 7 | export { default as ja } from "./locales/ja.js"; 8 | export { default as pt } from "./locales/pt.js"; 9 | export { default as ru } from "./locales/ru.js"; 10 | -------------------------------------------------------------------------------- /locales/locales/cn.js: -------------------------------------------------------------------------------- 1 | const lang = "zh-CN"; 2 | 3 | const calendar = { 4 | monthFull: [ 5 | "一月", 6 | "二月", 7 | "三月", 8 | "四月", 9 | "五月", 10 | "六月", 11 | "七月", 12 | "八月", 13 | "九月", 14 | "十月", 15 | "十一月", 16 | "十二月", 17 | ], 18 | monthShort: [ 19 | "一月", 20 | "二月", 21 | "三月", 22 | "四月", 23 | "五月", 24 | "六月", 25 | "七月", 26 | "八月", 27 | "九月", 28 | "十月", 29 | "十一月", 30 | "十二月", 31 | ], 32 | dayFull: [ 33 | "星期日", 34 | "星期一", 35 | "星期二", 36 | "星期三", 37 | "星期四", 38 | "星期五", 39 | "星期六", 40 | ], 41 | dayShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], 42 | hours: "小时", 43 | minutes: "分钟", 44 | done: "完成", 45 | clear: "清除", 46 | today: "今天", 47 | am: ["", ""], 48 | pm: ["", ""], 49 | 50 | weekStart: 7, 51 | clockFormat: 24, 52 | }; 53 | 54 | const core = { 55 | ok: "确定", 56 | cancel: "取消", 57 | select: "选择", 58 | "No data": "没有数据", 59 | }; 60 | 61 | const formats = { 62 | timeFormat: "%H:%i", 63 | dateFormat: "%Y-%m-%d", 64 | monthYearFormat: "%F %Y", 65 | yearFormat: "%Y", 66 | }; 67 | 68 | const data = { 69 | core, 70 | calendar, 71 | formats, 72 | lang, 73 | }; 74 | 75 | export default data; 76 | -------------------------------------------------------------------------------- /locales/locales/de.js: -------------------------------------------------------------------------------- 1 | const lang = "de-DE"; 2 | 3 | const calendar = { 4 | monthFull: [ 5 | "Januar", 6 | "Februar", 7 | "März", 8 | "April", 9 | "Mai", 10 | "Juni", 11 | "Juli", 12 | "August", 13 | "September", 14 | "Oktober", 15 | "November", 16 | "Dezember", 17 | ], 18 | monthShort: [ 19 | "Jan", 20 | "Feb", 21 | "Mrz", 22 | "Apr", 23 | "Mai", 24 | "Jun", 25 | "Jul", 26 | "Aug", 27 | "Sep", 28 | "Okt", 29 | "Nov", 30 | "Dez", 31 | ], 32 | dayFull: [ 33 | "Sonntag", 34 | "Montag", 35 | "Dienstag", 36 | "Mittwoch", 37 | "Donnerstag", 38 | "Freitag", 39 | "Samstag", 40 | ], 41 | dayShort: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], 42 | hours: "Stunden", 43 | minutes: "Minuten", 44 | done: "Fertig", 45 | clear: "Entfernen", 46 | today: "Heute", 47 | 48 | weekStart: 1, 49 | clockFormat: 24, 50 | }; 51 | 52 | const core = { 53 | ok: "OK", 54 | cancel: "Abbrechen", 55 | select: "Auswählen", 56 | "No data": "Keine Daten", 57 | }; 58 | 59 | const formats = { 60 | timeFormat: "%H:%i", 61 | dateFormat: "%d.%m.%Y", 62 | monthYearFormat: "%F %Y", 63 | yearFormat: "%Y", 64 | }; 65 | 66 | const data = { 67 | core, 68 | calendar, 69 | formats, 70 | lang, 71 | }; 72 | 73 | export default data; 74 | -------------------------------------------------------------------------------- /locales/locales/en.js: -------------------------------------------------------------------------------- 1 | const lang = "en-US"; 2 | 3 | const calendar = { 4 | monthFull: [ 5 | "January", 6 | "February", 7 | "March", 8 | "April", 9 | "May", 10 | "June", 11 | "July", 12 | "August", 13 | "September", 14 | "October", 15 | "November", 16 | "December", 17 | ], 18 | monthShort: [ 19 | "Jan", 20 | "Feb", 21 | "Mar", 22 | "Apr", 23 | "May", 24 | "Jun", 25 | "Jul", 26 | "Aug", 27 | "Sep", 28 | "Oct", 29 | "Nov", 30 | "Dec", 31 | ], 32 | dayFull: [ 33 | "Sunday", 34 | "Monday", 35 | "Tuesday", 36 | "Wednesday", 37 | "Thursday", 38 | "Friday", 39 | "Saturday", 40 | ], 41 | dayShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], 42 | hours: "Hours", 43 | minutes: "Minutes", 44 | done: "Done", 45 | clear: "Clear", 46 | today: "Today", 47 | am: ["am", "AM"], 48 | pm: ["pm", "PM"], 49 | 50 | weekStart: 7, 51 | clockFormat: 24, 52 | }; 53 | 54 | const core = { 55 | ok: "OK", 56 | cancel: "Cancel", 57 | select: "Select", 58 | "No data": "No data", 59 | }; 60 | 61 | const formats = { 62 | timeFormat: "%H:%i", 63 | dateFormat: "%m/%d/%Y", 64 | monthYearFormat: "%F %Y", 65 | yearFormat: "%Y", 66 | }; 67 | 68 | const data = { 69 | core, 70 | calendar, 71 | formats, 72 | lang, 73 | }; 74 | 75 | export default data; 76 | -------------------------------------------------------------------------------- /locales/locales/es.js: -------------------------------------------------------------------------------- 1 | const lang = "es-ES"; 2 | 3 | const calendar = { 4 | monthFull: [ 5 | "enero", 6 | "febrero", 7 | "marzo", 8 | "abril", 9 | "mayo", 10 | "junio", 11 | "julio", 12 | "agosto", 13 | "septiembre", 14 | "octubre", 15 | "noviembre", 16 | "diciembre", 17 | ], 18 | monthShort: [ 19 | "ene", 20 | "feb", 21 | "mar", 22 | "abr", 23 | "may", 24 | "jun", 25 | "jul", 26 | "ago", 27 | "sep", 28 | "oct", 29 | "nov", 30 | "dic", 31 | ], 32 | dayFull: [ 33 | "domingo", 34 | "lunes", 35 | "martes", 36 | "miércoles", 37 | "jueves", 38 | "viernes", 39 | "sábado", 40 | ], 41 | dayShort: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"], 42 | hours: "Horas", 43 | minutes: "Minutos", 44 | done: "Listo", 45 | clear: "Reinicio", 46 | today: "Hoy", 47 | 48 | weekStart: 1, 49 | clockFormat: 24, 50 | }; 51 | 52 | const core = { 53 | ok: "OK", 54 | cancel: "Cancelar", 55 | select: "Seleccionar", 56 | "No data": "Sin datos", 57 | }; 58 | 59 | const formats = { 60 | timeFormat: "%H:%i", 61 | dateFormat: "%d/%m/%Y", 62 | monthYearFormat: "%F %Y", 63 | yearFormat: "%Y", 64 | }; 65 | 66 | const data = { 67 | core, 68 | calendar, 69 | formats, 70 | lang, 71 | }; 72 | 73 | export default data; 74 | -------------------------------------------------------------------------------- /locales/locales/fr.js: -------------------------------------------------------------------------------- 1 | const lang = "fr-FR"; 2 | 3 | const calendar = { 4 | monthFull: [ 5 | "Janvier", 6 | "Février", 7 | "Mars", 8 | "Avril", 9 | "Mai", 10 | "Juin", 11 | "Juillet", 12 | "Août", 13 | "Septembre", 14 | "Octobre", 15 | "Novembre", 16 | "Décembre", 17 | ], 18 | monthShort: [ 19 | "Jan", 20 | "Fév", 21 | "Mar", 22 | "Avr", 23 | "Mai", 24 | "Juin", 25 | "Juil", 26 | "Aôu", 27 | "Sep", 28 | "Oct", 29 | "Nov", 30 | "Déc", 31 | ], 32 | dayFull: [ 33 | "Dimanche", 34 | "Lundi", 35 | "Mardi", 36 | "Mercredi", 37 | "Jeudi", 38 | "Vendredi", 39 | "Samedi", 40 | ], 41 | dayShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"], 42 | hours: "Heures", 43 | minutes: "Minutes", 44 | done: "Fini", 45 | clear: "Effacer", 46 | today: "Aujourd'hui", 47 | 48 | weekStart: 1, 49 | clockFormat: 24, 50 | }; 51 | 52 | const core = { 53 | ok: "OK", 54 | cancel: "Annuler", 55 | select: "Sélectionner", 56 | "No data": "Pas de données", 57 | }; 58 | 59 | const formats = { 60 | timeFormat: "%H:%i", 61 | dateFormat: "%d/%m/%Y", 62 | monthYearFormat: "%F %Y", 63 | yearFormat: "%Y", 64 | }; 65 | 66 | const data = { 67 | core, 68 | calendar, 69 | formats, 70 | lang, 71 | }; 72 | 73 | export default data; 74 | -------------------------------------------------------------------------------- /locales/locales/it.js: -------------------------------------------------------------------------------- 1 | const lang = "it-IT"; 2 | 3 | const calendar = { 4 | monthFull: [ 5 | "gennaio", 6 | "febbraio", 7 | "marzo", 8 | "aprile", 9 | "maggio", 10 | "giugno", 11 | "luglio", 12 | "agosto", 13 | "settembre", 14 | "ottobre", 15 | "novembre", 16 | "dicembre", 17 | ], 18 | monthShort: [ 19 | "gen", 20 | "feb", 21 | "mar", 22 | "apr", 23 | "mag", 24 | "giu", 25 | "lug", 26 | "ago", 27 | "set", 28 | "ott", 29 | "nov", 30 | "dic", 31 | ], 32 | dayFull: [ 33 | "domenica", 34 | "lunedì", 35 | "martedì", 36 | "mercoledì", 37 | "giovedì", 38 | "venerdì", 39 | "sabato", 40 | ], 41 | dayShort: ["dom", "lun", "mar", "mer", "gio", "ven", "sab"], 42 | hours: "Orario", 43 | minutes: "Minuti", 44 | done: "Pronto", 45 | clear: "Pulisci", 46 | today: "Oggi", 47 | 48 | weekStart: 1, 49 | clockFormat: 24, 50 | }; 51 | 52 | const core = { 53 | ok: "OK", 54 | cancel: "Annullare", 55 | select: "Seleziona", 56 | "No data": "Nessun dato", 57 | }; 58 | 59 | const formats = { 60 | timeFormat: "%H:%i", 61 | dateFormat: "%d/%m/%Y", 62 | monthYearFormat: "%F %Y", 63 | yearFormat: "%Y", 64 | }; 65 | 66 | const data = { 67 | core, 68 | calendar, 69 | formats, 70 | lang, 71 | }; 72 | 73 | export default data; 74 | -------------------------------------------------------------------------------- /locales/locales/ja.js: -------------------------------------------------------------------------------- 1 | const lang = "ja-JP"; 2 | 3 | const calendar = { 4 | monthFull: [ 5 | "1月", 6 | "2月", 7 | "3月", 8 | "4月", 9 | "5月", 10 | "6月", 11 | "7月", 12 | "8月", 13 | "9月", 14 | "10月", 15 | "11月", 16 | "12月", 17 | ], 18 | monthShort: [ 19 | "1月", 20 | "2月", 21 | "3月", 22 | "4月", 23 | "5月", 24 | "6月", 25 | "7月", 26 | "8月", 27 | "9月", 28 | "10月", 29 | "11月", 30 | "12月", 31 | ], 32 | dayFull: [ 33 | "日曜日", 34 | "月曜日", 35 | "火曜日", 36 | "水曜日", 37 | "木曜日", 38 | "金曜日", 39 | "土曜日", 40 | ], 41 | dayShort: ["日", "月", "火", "水", "木", "金", "土"], 42 | hours: "営業時間", 43 | minutes: "分", 44 | done: "レディー", 45 | clear: "削除する", 46 | today: "今日", 47 | 48 | weekStart: 1, 49 | clockFormat: 24, 50 | }; 51 | 52 | const core = { 53 | ok: "OK", 54 | cancel: "取り消す", 55 | select: "選択", 56 | "No data": "データが見つかりませんでした", 57 | }; 58 | 59 | const formats = { 60 | timeFormat: "%H:%i", 61 | dateFormat: "%Y年%m月%d日", 62 | monthYearFormat: "%m月%Y年", 63 | yearFormat: "%Y年", 64 | }; 65 | 66 | const data = { 67 | core, 68 | calendar, 69 | formats, 70 | lang, 71 | }; 72 | 73 | export default data; 74 | -------------------------------------------------------------------------------- /locales/locales/pt.js: -------------------------------------------------------------------------------- 1 | const lang = "pt-PT"; 2 | 3 | const calendar = { 4 | monthFull: [ 5 | "Janeiro", 6 | "Fevereiro", 7 | "Março", 8 | "Abril", 9 | "Maio", 10 | "Junho", 11 | "Julho", 12 | "Agosto", 13 | "Setembro", 14 | "Outubro", 15 | "Novembro", 16 | "Dezembro", 17 | ], 18 | monthShort: [ 19 | "Jan", 20 | "Fev", 21 | "Mar", 22 | "Abr", 23 | "Mai", 24 | "Jun", 25 | "Jul", 26 | "Ago", 27 | "Set", 28 | "Out", 29 | "Nov", 30 | "Dez", 31 | ], 32 | dayFull: [ 33 | "Domingo", 34 | "Segunda-Feira", 35 | "Terça-Feira", 36 | "Quarta-Feira", 37 | "Quinta-Feira", 38 | "Sexta-Feira", 39 | "Sábado", 40 | ], 41 | dayShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"], 42 | hours: "Horas", 43 | minutes: "Minutos", 44 | done: "Feito", 45 | clear: "Limpar", 46 | today: "Hoje", 47 | 48 | weekStart: 1, 49 | clockFormat: 24, 50 | }; 51 | 52 | const core = { 53 | ok: "OK", 54 | cancel: "Cancelar", 55 | select: "Selecionar", 56 | "No data": "Sem dados", 57 | }; 58 | 59 | const formats = { 60 | timeFormat: "%H:%i", 61 | dateFormat: "%d/%m/%Y", 62 | monthYearFormat: "%F %Y", 63 | yearFormat: "%Y", 64 | }; 65 | 66 | const data = { 67 | core, 68 | calendar, 69 | formats, 70 | lang, 71 | }; 72 | 73 | export default data; 74 | -------------------------------------------------------------------------------- /locales/locales/ru.js: -------------------------------------------------------------------------------- 1 | const lang = "ru-RU"; 2 | 3 | const calendar = { 4 | monthFull: [ 5 | "Январь", 6 | "Февраль", 7 | "Март", 8 | "Апрель", 9 | "Maй", 10 | "Июнь", 11 | "Июль", 12 | "Август", 13 | "Сентябрь", 14 | "Oктябрь", 15 | "Ноябрь", 16 | "Декабрь", 17 | ], 18 | monthShort: [ 19 | "Янв", 20 | "Фев", 21 | "Maр", 22 | "Aпр", 23 | "Maй", 24 | "Июн", 25 | "Июл", 26 | "Aвг", 27 | "Сен", 28 | "Окт", 29 | "Ноя", 30 | "Дек", 31 | ], 32 | dayFull: [ 33 | "Воскресенье", 34 | "Понедельник", 35 | "Вторник", 36 | "Среда", 37 | "Четверг", 38 | "Пятница", 39 | "Суббота", 40 | ], 41 | dayShort: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], 42 | hours: "Часы", 43 | minutes: "Минуты", 44 | done: "Гoтовo", 45 | clear: "Очистить", 46 | today: "Сегодня", 47 | 48 | weekStart: 1, 49 | clockFormat: 24, 50 | }; 51 | 52 | const core = { 53 | ok: "OK", 54 | cancel: "Отмена", 55 | select: "Выбрать", 56 | "No data": "Нет данных", 57 | }; 58 | 59 | const formats = { 60 | timeFormat: "%H:%i", 61 | dateFormat: "%d.%m.%Y", 62 | monthYearFormat: "%F %Y", 63 | yearFormat: "%Y", 64 | }; 65 | 66 | const data = { 67 | core, 68 | calendar, 69 | formats, 70 | lang, 71 | }; 72 | 73 | export default data; 74 | -------------------------------------------------------------------------------- /locales/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wx-core-locales", 3 | "version": "2.1.1", 4 | "description": "Locales for WX Core widgets", 5 | "type": "module", 6 | "main": "index.js", 7 | "scripts": { 8 | "build": "true", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [ 12 | "wx", 13 | "locales" 14 | ], 15 | "author": "", 16 | "license": "MIT" 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "wx-core", 4 | "workspaces": [ 5 | "svelte", 6 | "locales", 7 | "site" 8 | ], 9 | "scripts": { 10 | "build:deps": "true", 11 | "build:site": "cd site && yarn build", 12 | "build:tests": "cd svelte && yarn build:tests", 13 | "build": "cd svelte && yarn build", 14 | "lint": "yarn eslint ./svelte/src ./svelte/demos ./locales", 15 | "prepare": "husky", 16 | "start:demos": "cd svelte && yarn start", 17 | "start:site": "cd site && yarn start", 18 | "start:tests": "cd svelte && yarn start:tests", 19 | "start": "cd svelte && yarn start", 20 | "test:cypress": "cd svelte && yarn test:cypress", 21 | "test": "true" 22 | }, 23 | "devDependencies": { 24 | "@sveltejs/vite-plugin-svelte": "4.0.0", 25 | "@vitest/coverage-v8": "1.6.0", 26 | "wx-vite-tools": "1.0.5", 27 | "autoprefixer": "10.4.20", 28 | "cypress": "13.6.4", 29 | "eslint": "9.14.0", 30 | "eslint-config-prettier": "9.1.0", 31 | "eslint-plugin-cypress": "4.1.0", 32 | "eslint-plugin-svelte": "2.46.0", 33 | "eslint-plugin-vitest": "0.5.4", 34 | "husky": "9.1.6", 35 | "lint-staged": "15.2.10", 36 | "npm-run-all": "4.1.5", 37 | "postcss": "8.4.47", 38 | "prettier": "3.3.3", 39 | "prettier-plugin-svelte": "3.2.7", 40 | "rollup-plugin-visualizer": "5.12.0", 41 | "shx": "0.3.4", 42 | "svelte": "5.1.9", 43 | "svelte-spa-router": "4.0.1", 44 | "typescript-eslint": "8.13.0", 45 | "typescript": "5.6.3", 46 | "vite-plugin-conditional-compile": "1.4.5", 47 | "vite-plugin-dts": "3.7.2", 48 | "vite": "5.4.10", 49 | "vitest": "1.5.0" 50 | }, 51 | "lint-staged": { 52 | "*.{ts,js,svelte}": [ 53 | "eslint --fix --no-warn-ignored", 54 | "prettier --write" 55 | ], 56 | "*.{css,md,json}": [ 57 | "prettier --write" 58 | ] 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # SVAR Svelte Core | UI Library 4 | 5 |
6 | 7 |
8 | 9 | :globe_with_meridians: [Website](https://svar.dev/svelte/core/) • :bulb: [Getting Started](https://docs.svar.dev/svelte/core/getting_started/) • :eyes: [Demos](https://docs.svar.dev/svelte/core/samples/#/calendar/willow) 10 | 11 |
12 | 13 |
14 | 15 | [![npm](https://img.shields.io/npm/v/wx-svelte-core.svg)](https://www.npmjs.com/package/wx-svelte-core) 16 | [![License](https://img.shields.io/github/license/svar-widgets/core)](https://github.com/svar-widgets/core/blob/main/license.txt) 17 | [![npm downloads](https://img.shields.io/npm/dm/wx-svelte-core.svg)](https://www.npmjs.com/package/wx-svelte-core) 18 | 19 |
20 | 21 | **SVAR Svelte Core** library offers a set of 20+ ready-made Svelte UI components: form controls, popups, date and time picker, toast notifications, and more. 22 | All components are lightweight, responsive, fast-performing, and available in light and dark skins. 23 | 24 |
25 | 26 | SVAR Core - Svelte UI Library 27 | 28 |
29 | 30 |
31 | 32 | SVAR Core library includes the following components: 33 | - buttons & form controls, 34 | - calendar (datepicker), 35 | - popups, 36 | - notifications, 37 | - sliding sidebar, 38 | - tabs, and more. 39 | 40 | 41 | Additionally, you can use these SVAR Svelte components to build unified app interfaces: 42 | - [Menu](https://github.com/svar-widgets/menu) - helps you create basic menu bar, actions or context menu; 43 | - [Toolbar](https://github.com/svar-widgets/toolbar) - allows you to create button and icon panels with configurable layouts; 44 | - [Tasklist](https://github.com/svar-widgets/tasklist) - task list component to add, edit, check or delete tasks; 45 | - [Comments](https://github.com/svar-widgets/comments) - nice-looking comments section; 46 | - [File uploader](https://github.com/svar-widgets/uploader) - simple file uploader component. 47 | 48 | ### :hammer_and_wrench: How to Use 49 | 50 | To start using components from the **Core** package, simply import the package and include the desired component in your Svelte file: 51 | 52 | ```svelte 53 | 56 | 57 | 58 | ``` 59 | 60 | See the [getting started guide](https://docs.svar.dev/svelte/core/getting_started/) to quickly set up and begin using SVAR Core components in your Svelte projects. 61 | 62 | ### :computer: How to Modify 63 | 64 | Typically, you don't need to modify the code. However, if you wish to do so, follow these steps: 65 | 66 | 1. Run `yarn` to install dependencies. Note that this project is a monorepo using `yarn` workspaces, so npm will not work 67 | 2. Start the project in development mode with `yarn start` 68 | 69 | ### :white_check_mark: Run Tests 70 | 71 | To run the test: 72 | 73 | 1. Start the test examples with: 74 | ```sh 75 | yarn start:tests 76 | ``` 77 | 2. In a separate console, run the end-to-end tests with: 78 | ```sh 79 | yarn test:cypress 80 | ``` 81 | 82 | ### :speech_balloon: Need Help? 83 | 84 | [Post an Issue](https://github.com/svar-widgets/core/issues/) or use our [community forum](https://forum.svar.dev). 85 | -------------------------------------------------------------------------------- /site/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Svelte Widgets 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /site/index.js: -------------------------------------------------------------------------------- 1 | import Demo from "./src/Demo.svelte"; 2 | import { mount } from "svelte"; 3 | 4 | mount(Demo, { 5 | target: document.querySelector("#wx_demo_area") || document.body, 6 | }); 7 | -------------------------------------------------------------------------------- /site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wx-site-svelte-core", 3 | "version": "2.1.1", 4 | "type": "module", 5 | "scripts": { 6 | "build": "vite build", 7 | "lint": "yarn eslint ./src", 8 | "start": "yarn vite --open" 9 | }, 10 | "license": "MIT", 11 | "dependencies": { 12 | "wx-svelte-core": "2.1.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /site/public/assets/avatars/avatar01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svar-widgets/core/1e09ae4e45180ebd91f69613ff078aa4a1364cb8/site/public/assets/avatars/avatar01.png -------------------------------------------------------------------------------- /site/public/assets/avatars/avatar04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svar-widgets/core/1e09ae4e45180ebd91f69613ff078aa4a1364cb8/site/public/assets/avatars/avatar04.png -------------------------------------------------------------------------------- /site/public/assets/avatars/avatar05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svar-widgets/core/1e09ae4e45180ebd91f69613ff078aa4a1364cb8/site/public/assets/avatars/avatar05.png -------------------------------------------------------------------------------- /site/public/assets/avatars/avatar06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svar-widgets/core/1e09ae4e45180ebd91f69613ff078aa4a1364cb8/site/public/assets/avatars/avatar06.png -------------------------------------------------------------------------------- /site/public/assets/avatars/avatar07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svar-widgets/core/1e09ae4e45180ebd91f69613ff078aa4a1364cb8/site/public/assets/avatars/avatar07.png -------------------------------------------------------------------------------- /site/public/assets/avatars/avatar09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svar-widgets/core/1e09ae4e45180ebd91f69613ff078aa4a1364cb8/site/public/assets/avatars/avatar09.png -------------------------------------------------------------------------------- /site/public/assets/avatars/avatar10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svar-widgets/core/1e09ae4e45180ebd91f69613ff078aa4a1364cb8/site/public/assets/avatars/avatar10.png -------------------------------------------------------------------------------- /site/public/assets/icons/Willow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /site/public/assets/icons/Willow_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /site/src/CustomCoreWidgets.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 |
20 |
21 |
22 | 23 | 46 | -------------------------------------------------------------------------------- /site/src/Demo.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | {#if themeSelect} 25 |
26 |
27 |
28 | Theme 29 | 30 |
31 |
32 |
33 |
34 |
35 |
36 | {:else} 37 |
38 | {/if} 39 | 40 | 41 |
42 | 43 | 76 | -------------------------------------------------------------------------------- /site/src/Main.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 |
13 | 14 |
15 | 16 | 17 | 18 | 19 |
20 |
21 |
22 | 23 | 46 | -------------------------------------------------------------------------------- /site/src/ThemeSelect.svelte: -------------------------------------------------------------------------------- 1 | 22 | 23 |
24 | 25 | {#snippet children(option)} 26 |
27 |
28 |
29 |
30 |
31 | {option.label} 32 |
33 | 51 | {/snippet} 52 |
53 |
54 | -------------------------------------------------------------------------------- /site/src/components/CalendarUploader.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | 7 | 11 |
12 | 13 | 32 | -------------------------------------------------------------------------------- /site/src/components/CustomThemeSelect.svelte: -------------------------------------------------------------------------------- 1 | 28 | 29 |
30 | 31 |
32 | 33 | 44 | -------------------------------------------------------------------------------- /site/src/components/Icons/LockIcon.svelte: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /site/src/components/RadioCheckboxes.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
15 |
16 | 17 |
18 | 19 | 28 | 29 | 71 | -------------------------------------------------------------------------------- /svelte/src/components/TwoState.svelte: -------------------------------------------------------------------------------- 1 | 31 | 32 | {#if value && active} 33 | 44 | {:else if children} 45 | 56 | {:else} 57 | 8 | 9 | 41 | -------------------------------------------------------------------------------- /svelte/src/components/calendar/Duodecade.svelte: -------------------------------------------------------------------------------- 1 | 53 | 54 |
55 | {#each years as y, i} 56 |
63 | {y} 64 |
65 | {/each} 66 |
67 |
68 | 69 |
70 | 71 | 110 | -------------------------------------------------------------------------------- /svelte/src/components/calendar/Header.svelte: -------------------------------------------------------------------------------- 1 | 28 | 29 |
30 | {#if part != "right"} 31 | 32 | 33 | onshift && onshift({ diff: -1, type })} 36 | > 37 | {:else}{/if} 38 | 39 | 40 | {label} 41 | {#if part != "left"} 42 | 43 | 44 | onshift && onshift({ diff: 1, type })} 47 | > 48 | {:else}{/if} 49 |
50 | 51 | 98 | -------------------------------------------------------------------------------- /svelte/src/components/calendar/Panel.svelte: -------------------------------------------------------------------------------- 1 | 52 | 53 |
56 |
57 |
58 |
59 | 68 | {#if type === "month" && buttons} 69 |
70 | {#if done} 71 |
72 | 75 |
76 | {/if} 77 |
78 | 81 |
82 |
83 | 86 |
87 |
88 | {/if} 89 |
90 |
91 |
92 | 93 | 126 | -------------------------------------------------------------------------------- /svelte/src/components/calendar/Year.svelte: -------------------------------------------------------------------------------- 1 | 47 | 48 |
49 | {#each months as month, i} 50 |
51 | {month} 52 |
53 | {/each} 54 |
55 |
56 | 57 |
58 | 59 | 95 | -------------------------------------------------------------------------------- /svelte/src/components/calendar/helpers.js: -------------------------------------------------------------------------------- 1 | import Month from "./Month.svelte"; 2 | import Year from "./Year.svelte"; 3 | import Duodecade from "./Duodecade.svelte"; 4 | 5 | export const configs = { 6 | month: { 7 | component: Month, 8 | next: nextMonth, 9 | prev: prevMonth, 10 | }, 11 | year: { 12 | component: Year, 13 | next: nextYear, 14 | prev: prevYear, 15 | }, 16 | duodecade: { 17 | component: Duodecade, 18 | next: nextDuodecade, 19 | prev: prevDuodecade, 20 | }, 21 | }; 22 | 23 | function prevMonth(current) { 24 | current = new Date(current); 25 | current.setMonth(current.getMonth() - 1); 26 | return current; 27 | } 28 | function nextMonth(current) { 29 | current = new Date(current); 30 | current.setMonth(current.getMonth() + 1); 31 | return current; 32 | } 33 | function prevYear(current) { 34 | current = new Date(current); 35 | current.setFullYear(current.getFullYear() - 1); 36 | return current; 37 | } 38 | function nextYear(current) { 39 | current = new Date(current); 40 | current.setFullYear(current.getFullYear() + 1); 41 | return current; 42 | } 43 | function prevDuodecade(current) { 44 | current = new Date(current); 45 | current.setFullYear(current.getFullYear() - 10); 46 | return current; 47 | } 48 | function nextDuodecade(current) { 49 | current = new Date(current); 50 | current.setFullYear(current.getFullYear() + 10); 51 | return current; 52 | } 53 | 54 | export function getPartValue(value, part) { 55 | let date; 56 | if (part === "normal") date = value; 57 | else { 58 | const { start, end } = value; 59 | if (part === "left") date = start; 60 | else if (part == "right") date = end; 61 | else date = start ? end : start; 62 | } 63 | 64 | return date; 65 | } 66 | -------------------------------------------------------------------------------- /svelte/src/components/helpers.js: -------------------------------------------------------------------------------- 1 | import { uid } from "wx-lib-dom"; 2 | 3 | export function popupContainer(node) { 4 | const id = uid(); 5 | node.setAttribute("data-wx-portal-root", id); 6 | } 7 | -------------------------------------------------------------------------------- /svelte/src/components/helpers/SuggestDropdown.svelte: -------------------------------------------------------------------------------- 1 | 27 | 28 | {#if navIndex !== null} 29 | navigate(null)}> 30 | 31 | 32 |
38 | {#if items.length} 39 | {#each items as data, index (data.id)} 40 |
45 | {#if children}{@render children({ 46 | option: data, 47 | })}{:else}{data.label}{/if} 48 |
49 | {/each} 50 | {:else} 51 |
{_("No data")}
52 | {/if} 53 |
54 |
55 | {/if} 56 | 57 | 89 | -------------------------------------------------------------------------------- /svelte/src/components/helpers/colorTransformator.js: -------------------------------------------------------------------------------- 1 | const colorTransformator = { 2 | _toHex: [ 3 | "0", 4 | "1", 5 | "2", 6 | "3", 7 | "4", 8 | "5", 9 | "6", 10 | "7", 11 | "8", 12 | "9", 13 | "A", 14 | "B", 15 | "C", 16 | "D", 17 | "E", 18 | "F", 19 | ], 20 | toHex(number, length) { 21 | number = parseInt(number, 10); 22 | let str = ""; 23 | while (number > 0) { 24 | str = this._toHex[number % 16] + str; 25 | number = Math.floor(number / 16); 26 | } 27 | while (str.length < length) str = `0${str}`; 28 | return str; 29 | }, 30 | rgbToHex(rgb) { 31 | let arr = []; 32 | if (typeof rgb === "string") 33 | rgb.replace(/[\d+.]+/g, v => arr.push(parseFloat(v))); 34 | else if (Array.isArray(rgb)) arr = rgb; 35 | 36 | //transparent 37 | if (arr[3] === 0) return ""; 38 | 39 | return arr 40 | .slice(0, 3) 41 | .map(n => { 42 | return this.toHex(Math.floor(n), 2); 43 | }) 44 | .join(""); 45 | }, 46 | hexToDec(hex) { 47 | return parseInt(hex, 16); 48 | }, 49 | // only handles the six-digit hex color format 50 | hexToRgb(hex) { 51 | hex = hex.charAt(0) === "#" ? hex.slice(1) : hex; 52 | const rgbPairs = hex.match(/.{1,2}/g); 53 | 54 | let [r, g, b] = rgbPairs; 55 | 56 | r = this.hexToDec(r); 57 | g = this.hexToDec(g); 58 | b = this.hexToDec(b); 59 | 60 | return [r, g, b]; 61 | }, 62 | hsvToRgb(h, s, v) { 63 | let hi, f, p, q, t, r, g, b; 64 | hi = Math.floor(h / 60) % 6; 65 | f = h / 60 - hi; 66 | p = v * (1 - s); 67 | q = v * (1 - f * s); 68 | t = v * (1 - (1 - f) * s); 69 | r = 0; 70 | g = 0; 71 | b = 0; 72 | switch (hi) { 73 | case 0: 74 | r = v; 75 | g = t; 76 | b = p; 77 | break; 78 | case 1: 79 | r = q; 80 | g = v; 81 | b = p; 82 | break; 83 | case 2: 84 | r = p; 85 | g = v; 86 | b = t; 87 | break; 88 | case 3: 89 | r = p; 90 | g = q; 91 | b = v; 92 | break; 93 | case 4: 94 | r = t; 95 | g = p; 96 | b = v; 97 | break; 98 | case 5: 99 | r = v; 100 | g = p; 101 | b = q; 102 | break; 103 | default: 104 | break; 105 | } 106 | r = Math.floor(r * 255); 107 | g = Math.floor(g * 255); 108 | b = Math.floor(b * 255); 109 | 110 | return [r, g, b]; 111 | }, 112 | rgbToHsv(r, g, b) { 113 | let s, h, v; 114 | r /= 255; 115 | g /= 255; 116 | b /= 255; 117 | let min = Math.min(r, g, b); 118 | let max = Math.max(r, g, b); 119 | h = 0; 120 | s = max === 0 ? 0 : 1 - min / max; 121 | v = max; 122 | if (max === min) { 123 | h = 0; 124 | } else if (max === r && g >= b) { 125 | h = (60 * (g - b)) / (max - min) + 0; 126 | } else if (max === r && g < b) { 127 | h = (60 * (g - b)) / (max - min) + 360; 128 | } else if (max === g) { 129 | h = (60 * (b - r)) / (max - min) + 120; 130 | } else if (max === b) { 131 | h = (60 * (r - g)) / (max - min) + 240; 132 | } 133 | 134 | return [h, s, v]; 135 | }, 136 | hexToHvs(hex) { 137 | const rgb = this.hexToRgb(hex); 138 | return this.rgbToHsv(...rgb); 139 | }, 140 | hvsToHex(h, v, s) { 141 | const rgb = this.hsvToRgb(h, v, s); 142 | return "#" + this.rgbToHex(rgb).toUpperCase(); 143 | }, 144 | }; 145 | 146 | export default colorTransformator; 147 | -------------------------------------------------------------------------------- /svelte/src/components/helpers/colorValidation.js: -------------------------------------------------------------------------------- 1 | const hexValidation = str => /^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(str); 2 | 3 | export function parseColor(value) { 4 | if (!value) return null; 5 | 6 | value = value.toString(16); 7 | 8 | if (value.charAt(0) === "#") value = value.slice(1); 9 | 10 | if (hexValidation(value)) { 11 | if (value.length === 3) { 12 | value = value 13 | .slice(0, 3) 14 | .split("") 15 | .reduce((a, b) => a + b + b, ""); 16 | } 17 | return `#${value.toUpperCase()}`; 18 | } 19 | 20 | return null; 21 | } 22 | -------------------------------------------------------------------------------- /svelte/src/components/helpers/listnav.js: -------------------------------------------------------------------------------- 1 | import { locateID } from "wx-lib-dom"; 2 | 3 | export function getListHandlers() { 4 | let navIndex = null; 5 | let isVisible = false; 6 | 7 | let list, options, navCallback, selectCallback; 8 | const init = (l, o, n, c) => { 9 | list = l; 10 | options = o; 11 | navCallback = n; 12 | selectCallback = c; 13 | }; 14 | 15 | const setNav = index => { 16 | navIndex = index; 17 | isVisible = navIndex !== null; 18 | navCallback(navIndex); 19 | }; 20 | const navigate = (dir, ev) => { 21 | const index = 22 | dir === null 23 | ? null 24 | : Math.max(0, Math.min(navIndex + dir, options.length - 1)); 25 | if (index === navIndex) return; 26 | setNav(index); 27 | 28 | if (list) scrollTo(index, ev); 29 | else requestAnimationFrame(() => scrollTo(index, ev)); 30 | }; 31 | 32 | const scrollTo = (navIndex, ev) => { 33 | if (navIndex !== null && list) { 34 | const next = list.querySelectorAll(`.wx-list > .wx-item`)[navIndex]; 35 | if (next) { 36 | next.scrollIntoView({ block: "nearest" }); 37 | if (ev) ev.preventDefault(); 38 | } 39 | } 40 | }; 41 | 42 | const move = ev => { 43 | const id = locateID(ev); 44 | // if we have id:"1", the locateID will return 1 as number 45 | // so using non-strict comparison 46 | const index = options.findIndex(a => a.id == id); 47 | 48 | if (index !== navIndex) { 49 | setNav(index); 50 | } 51 | }; 52 | 53 | const keydown = (ev, position) => { 54 | switch (ev.code) { 55 | case "Enter": 56 | if (isVisible) selectCallback(); 57 | else setNav(0); 58 | break; 59 | 60 | case "Space": 61 | if (!isVisible) setNav(0); 62 | break; 63 | 64 | case "Escape": 65 | navCallback((navIndex = null)); 66 | break; 67 | 68 | case "Tab": 69 | navCallback((navIndex = null)); 70 | break; 71 | 72 | case "ArrowDown": 73 | navigate(isVisible ? 1 : position || 0, ev); 74 | break; 75 | 76 | case "ArrowUp": 77 | navigate(isVisible ? -1 : position || 0, ev); 78 | break; 79 | 80 | default: 81 | break; 82 | } 83 | }; 84 | 85 | return { move, keydown, init, navigate }; 86 | } 87 | -------------------------------------------------------------------------------- /svelte/src/components/helpers/sliderMove.js: -------------------------------------------------------------------------------- 1 | export function sliderMove(node, config) { 2 | const slider = node.firstChild; 3 | const { moveBlockSlider, moveLineSlider } = config || {}; 4 | 5 | function down(ev) { 6 | move(ev); 7 | 8 | slider.focus(); 9 | 10 | window.addEventListener("mousemove", move); 11 | window.addEventListener("mouseup", up); 12 | } 13 | 14 | function move(ev) { 15 | let x, y, dx, dy; 16 | 17 | const coords = node.getBoundingClientRect(); 18 | x = coords.left; 19 | y = coords.top; 20 | 21 | dx = ev.clientX - x; 22 | dy = ev.clientY - y; 23 | 24 | if (moveBlockSlider) config.moveBlockSlider(dx, dy); 25 | if (moveLineSlider) config.moveLineSlider(dx); 26 | } 27 | 28 | function up() { 29 | slider.blur(); 30 | 31 | window.removeEventListener("mousemove", move); 32 | window.removeEventListener("mouseup", up); 33 | } 34 | 35 | node.addEventListener("mousedown", down); 36 | 37 | return { 38 | destroy() { 39 | node.removeEventListener("mousedown", down); 40 | }, 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /svelte/src/index.js: -------------------------------------------------------------------------------- 1 | export { default as TextArea } from "./components/TextArea.svelte"; 2 | export { default as Button } from "./components/Button.svelte"; 3 | export { default as Checkbox } from "./components/Checkbox.svelte"; 4 | export { default as CheckboxGroup } from "./components/CheckboxGroup.svelte"; 5 | export { default as ColorSelect } from "./components/ColorSelect.svelte"; 6 | export { default as ColorBoard } from "./components/ColorBoard.svelte"; 7 | export { default as ColorPicker } from "./components/ColorPicker.svelte"; 8 | export { default as Combo } from "./components/Combo.svelte"; 9 | export { default as DatePicker } from "./components/DatePicker.svelte"; 10 | export { default as DateRangePicker } from "./components/DateRangePicker.svelte"; 11 | export { default as Icon } from "./components/Icon.svelte"; 12 | export { default as MultiCombo } from "./components/MultiCombo.svelte"; 13 | export { default as Popup } from "./components/Popup.svelte"; 14 | export { default as Dropdown } from "./components/Dropdown.svelte"; 15 | export { default as Pager } from "./components/Pager.svelte"; 16 | export { default as RadioButton } from "./components/RadioButton.svelte"; 17 | export { default as RadioButtonGroup } from "./components/RadioButtonGroup.svelte"; 18 | export { default as RichSelect } from "./components/RichSelect.svelte"; 19 | export { default as Segmented } from "./components/Segmented.svelte"; 20 | export { default as Select } from "./components/Select.svelte"; 21 | export { default as Slider } from "./components/Slider.svelte"; 22 | export { default as Switch } from "./components/Switch.svelte"; 23 | export { default as Tabs } from "./components/Tabs.svelte"; 24 | export { default as Text } from "./components/Text.svelte"; 25 | export { default as Counter } from "./components/Counter.svelte"; 26 | export { default as Globals } from "./components/Globals.svelte"; 27 | export { default as Field } from "./components/Field.svelte"; 28 | export { default as Calendar } from "./components/Calendar.svelte"; 29 | export { default as Month } from "./components/calendar/Month.svelte"; 30 | export { default as RangeCalendar } from "./components/RangeCalendar.svelte"; 31 | export { default as TimePicker } from "./components/TimePicker.svelte"; 32 | export { default as TwoState } from "./components/TwoState.svelte"; 33 | export { default as Modal } from "./components/Modal.svelte"; 34 | export { default as ModalArea } from "./components/ModalArea.svelte"; 35 | export { default as SideArea } from "./components/SideArea.svelte"; 36 | export { default as Portal } from "./components/Portal.svelte"; 37 | 38 | export { default as Material } from "./themes/Material.svelte"; 39 | export { default as Willow } from "./themes/Willow.svelte"; 40 | export { default as WillowDark } from "./themes/WillowDark.svelte"; 41 | 42 | export { default as Locale } from "./Locale.svelte"; 43 | export { locale } from "wx-lib-dom"; 44 | 45 | export { popupContainer } from "./components/helpers"; 46 | export { default as SuggestDropdown } from "./components/helpers/SuggestDropdown.svelte"; 47 | 48 | export { en } from "wx-core-locales"; 49 | 50 | import { setEnv } from "wx-lib-dom"; 51 | import { env } from "wx-lib-svelte"; 52 | setEnv(env); 53 | -------------------------------------------------------------------------------- /svelte/src/themes/FontOpenSans.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | {@html ``} 37 | -------------------------------------------------------------------------------- /svelte/src/themes/FonttRoboto.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | {@html ``} 21 | -------------------------------------------------------------------------------- /svelte/svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; 2 | 3 | export default { 4 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 5 | // for more information about preprocessors 6 | preprocess: vitePreprocess(), 7 | }; 8 | -------------------------------------------------------------------------------- /svelte/tests/Index.svelte: -------------------------------------------------------------------------------- 1 | 47 | 48 | 49 | 50 | 51 | 52 |
53 | 54 | 55 | 56 | 57 | 58 |
59 | 60 | 98 | -------------------------------------------------------------------------------- /svelte/tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Svelte Widgets 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /svelte/tests/index.js: -------------------------------------------------------------------------------- 1 | import Demos from "./Index.svelte"; 2 | import { mount } from "svelte"; 3 | 4 | mount(Demos, { 5 | target: document.querySelector("#wx_demo_area") || document.body, 6 | }); 7 | -------------------------------------------------------------------------------- /svelte/tests/routes.js: -------------------------------------------------------------------------------- 1 | export const links = []; 2 | -------------------------------------------------------------------------------- /svelte/vite.config.js: -------------------------------------------------------------------------------- 1 | import { loadEnv } from "vite"; 2 | import { resolve } from "path"; 3 | import { existsSync } from "fs"; 4 | import { svelte } from "@sveltejs/vite-plugin-svelte"; 5 | import { visualizer } from "rollup-plugin-visualizer"; 6 | import { waitChanges, waitOn } from "wx-vite-tools"; 7 | import conditionalCompile from "vite-plugin-conditional-compile"; 8 | import pkg from "./package.json" with { type: "json" }; 9 | 10 | export default async ({ mode }) => { 11 | process.env = { ...process.env, ...loadEnv(mode, process.cwd(), "WX") }; 12 | const files = []; 13 | 14 | if (mode !== "production") { 15 | const paths = [ 16 | resolve(__dirname, "../store/dist/index.js"), 17 | resolve(__dirname, "../provider/dist/index.js"), 18 | ]; 19 | 20 | paths.forEach(path => { 21 | if (existsSync(path)) { 22 | files.push(path); 23 | } 24 | }); 25 | } 26 | 27 | const plugins = []; 28 | 29 | if (files.length) plugins.push(waitChanges({ files })); 30 | if (mode !== "development") plugins.push(conditionalCompile()); 31 | plugins.push(svelte({})); 32 | 33 | const name = pkg.productTag; 34 | 35 | let build, 36 | publicDir = resolve(__dirname, "public"), 37 | server = {}, 38 | base = ""; 39 | 40 | if (mode === "test") { 41 | build = { 42 | rollupOptions: { 43 | input: { tests: resolve(__dirname, "tests/index.html") }, 44 | }, 45 | }; 46 | server.port = 5100; 47 | } else { 48 | build = { 49 | rollupOptions: { 50 | input: { index: resolve(__dirname, "index.html") }, 51 | }, 52 | }; 53 | } 54 | 55 | if (process.env.WX_BUILD_STATS) { 56 | build = { 57 | lib: { 58 | entry: resolve(__dirname, "src/index.js"), 59 | name, 60 | formats: ["es"], 61 | fileName: format => `${name}.${format}.js`, 62 | }, 63 | outDir: "./dist", 64 | sourcemap: true, 65 | minify: true, 66 | target: "esnext", 67 | }; 68 | publicDir = false; 69 | plugins.push(visualizer({ filename: "dist/stats.html" })); 70 | } 71 | 72 | if (files.length) await waitOn({ files }); 73 | 74 | return { 75 | base, 76 | build, 77 | publicDir, 78 | resolve: { dedupe: ["svelte"] }, 79 | plugins, 80 | server, 81 | watch: { 82 | persistent: true, 83 | include: ["src/**/*.ts", "src/**/*.js"], 84 | }, 85 | }; 86 | }; 87 | --------------------------------------------------------------------------------