From c953dcae811218a7e17f710f66b5bc901f7a1f97 Mon Sep 17 00:00:00 2001 From: Nigel Breslaw Date: Mon, 9 Dec 2024 23:54:10 +0200 Subject: [PATCH] 1.9 docs: Slint language philosophy (#7039) --- docs/astro/ec.config.mjs | 11 +- docs/astro/package.json | 1 + .../language/concepts/slint-language.mdx | 148 +++++++++++++++++- docs/astro/src/utils/link-data.json | 3 + pnpm-lock.yaml | 10 ++ 5 files changed, 171 insertions(+), 2 deletions(-) diff --git a/docs/astro/ec.config.mjs b/docs/astro/ec.config.mjs index 17b2e21e291..443cd2357e9 100644 --- a/docs/astro/ec.config.mjs +++ b/docs/astro/ec.config.mjs @@ -3,6 +3,7 @@ import { definePlugin } from "@expressive-code/core"; import { h } from "@expressive-code/core/hast"; import fs from "node:fs"; +import { pluginLineNumbers } from "@expressive-code/plugin-line-numbers"; function sideBorder() { return definePlugin({ @@ -169,7 +170,15 @@ function workersPlaygroundButton() { } export default { - plugins: [workersPlaygroundButton(), sideBorder(), languageLabel()], + plugins: [ + workersPlaygroundButton(), + sideBorder(), + languageLabel(), + pluginLineNumbers(), + ], + defaultProps: { + showLineNumbers: false, + }, themes: ["dark-plus", "light-plus"], styleOverrides: { borderRadius: "0.4rem", diff --git a/docs/astro/package.json b/docs/astro/package.json index bfb851d25c4..5344b425873 100644 --- a/docs/astro/package.json +++ b/docs/astro/package.json @@ -20,6 +20,7 @@ "dependencies": { "@astrojs/check": "0.9.4", "@astrojs/starlight": "0.29.2", + "@expressive-code/plugin-line-numbers": "0.38.3", "@types/node": "20.16.10", "astro": "4.16.16", "playwright": "1.49.0", diff --git a/docs/astro/src/content/docs/guide/language/concepts/slint-language.mdx b/docs/astro/src/content/docs/guide/language/concepts/slint-language.mdx index 579fd322338..d393d03de11 100644 --- a/docs/astro/src/content/docs/guide/language/concepts/slint-language.mdx +++ b/docs/astro/src/content/docs/guide/language/concepts/slint-language.mdx @@ -4,4 +4,150 @@ title: Slint Language description: Slint Language --- -Component basics. It's components all the way down... \ No newline at end of file +import Link from '/src/components/Link.astro'; + +The objective of the concepts section of the guide is to give you an overview of the language from a high level. If you want to +dive straight in then the details check out the the and language reference +sections. + +This section gives you an insight into the thinking behind the language and the core concepts it is made up from. + + + +## Why Slint? + +The Slint language describes your application's User Interface in a declarative way. + +A User Interface is quite different from abstract code. It's made up +of text, images, colors, animations, and so on. Even though it's a mirage, the buttons and elements do not +really exist in the physical world, it's meant to look and behave as if it does. Buttons have pressed effects, +lists can be flicked and behave as if they had real inertia. When being designed they are described in terms +of UI components, forms, and views. + +Meanwhile the world of code is a quite different abstraction. It's made up of functions, variables, and so on. +Even when some aspects of a UI exist such as buttons and menus they also go hand in hand with a lot of code to +manage the implementation details. + +```js +const button = document.createElement('button'); +button.textContent = 'Click me'; +document.body.appendChild(button); +``` + +Take this simple web example. A button is created. Then a property to show 'Click me' text is text. At this point +technically the button exists, but it won't show up as its not attached to anything. So the final line +makes it a parent of the main view. + +```js +const buttonWithListener = document.createElement('button'); +buttonWithListener.textContent = 'Click me'; +buttonWithListener.addEventListener('click', () => { + console.log('Button clicked!'); +}); +document.body.appendChild(buttonWithListener); +``` + +In this second example a button is created and an event listener is added. Within that is a callback +function to log out that the button is pressed. It's a lot of code to so simple things. + +Its quite abstract. For example once a few more buttons and components are added its almost impossible +to be able to think how the real interface would look. It's hard to think about the design of a UI +using this kind of code. + +It's also too complex to edit without understanding how to code. This means UI designers cannot work +hands on to ensure all their design intent is implemented. They are forced to use other tools and frameworks +to crate prototypes and design guides that may look or behave differently to the software used to implementat +the production UI. It should not have to be this way. + +## Declartive style + +There have been attempts to make describing a UI in code more declarative. For example [React](https://reactjs.org/) +and [SwiftUI](https://developer.apple.com/xcode/swiftui/). + + +```jsx +function ContentView() { + return ( +

+ Hello World +

+ ); +} +``` + +```swift +struct ContentView: View { + var body: some View { + Text("Hello World") + .font(.title) + .foregroundColor(.green) + } +} +``` + +These languages take normal code and let it be used in a declartive way. But it's +still functions with arguments that act as properties. It is simpler and behaviour +such as parent child relationships can be inferred. + +For Slint instead of tweaking a normal language to be more declarative we instead +created a pure declarative language from the ground up. + + +## The Business Logic Problem + +One attempt to solve the problem of describing a UI in code has been to create a separate static markup language. +Platforms such as Android and [WPF](https://docs.microsoft.com/en-us/dotnet/desktop/wpf/) have done this. The UI +is described in an XML like format. While the rest of the code is written in both a separate language and also +separate files. Known as a code behind file. The issue here is that XML, despite claims to the contrary, is not +human readable or editable. It's also too static and rigid and it can be frustrating to jump between the UI file +and the separate code behind file to describe the behavior of the UI. + +Meanwhile the React web framework has solved this problem by using JSX. HTML, CSS and JavaScript can be mixed +together in a single file. On one hand this is great as it means you can use the same language to describe the UI +layout and behavior. On the other hand there is no limit to what code you can put in a JSX file. Logic for handling +network requests, processing data and pretty much anything quickly ends up mixed in with UI code. It leads to an +issue where it can be fast to create an initial application, but it becomes so hard to maintain that it's too +slow or costly to evolve the application. + +## A True Declarative UI Language + +Slint provides a declarative language to describe an applications user interface + +```slint showLineNumbers=true no-test +Rectangle { + Button { + text: "Click me!"; + clicked => { + debug("Button clicked!"); + } + } +} +``` + +If you can understand this Slint code you already have grasped a majority of how simple to use the language is. +On line 2 we declare a `Button`. On line 3 we set its `text` property to `"Click me!"` and on line 4 +we set a callback to print out "Button clicked!" to the console via the built in `debug` function. + +The Slint compiler will take this code and see it needs to generate a Rectangle that has a Button as a child. +Similarly, when the clicked callback activates, it will run the `debug` function. There is no need to think +about component and even listener life cycles. + +With the Slint language you can think much more closely to how a user interface looks and behaves. Instead of +describing the 'how', the how should the details be implemented in traditional code, you instead "declare" how +the interface should look and behave. Hence Slint being a 'declarative UI language'. + +It's not only simpler for software developers to use, it's also now something designers can potentially edit or +more easily contribute to. + +Slint isn't the first declarative UI language, but it takes advantage of being able to learn from earlier more +complex attempts that hinted at the potential of a declarative UI language to finalize into a modern and complete +system. + +At first glance it has the simplicity of a static markup language, but with a modern take that removes things like +angle brackets and tags. But also dynamic features such as complex property expressions, functions, callbacks, +and automatic reactivity. However these can only be used in the context of what helps a UI component. If you want +to make network requests, process data, or many other things that count as 'business logic' then those have to live +in separate files written in Rust, C++, JavaScript, etc. Slint allows you to express any UI and only the UI. + +It then provides a system of adapters to allow the business logic side of the app to easily communicate with the UI +and visa versa. diff --git a/docs/astro/src/utils/link-data.json b/docs/astro/src/utils/link-data.json index 13d86aaffd2..bab9410a9e5 100644 --- a/docs/astro/src/utils/link-data.json +++ b/docs/astro/src/utils/link-data.json @@ -38,6 +38,9 @@ "EnumType": { "href": "/reference/global-structs-enums" }, + "slintFile": { + "href": "/guide/language/coding/file" + }, "float": { "href": "/reference/primitive-types#float" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e623e26d460..864de572b6d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,6 +71,9 @@ importers: '@astrojs/starlight': specifier: 0.29.2 version: 0.29.2(astro@4.16.16(@types/node@20.16.10)(rollup@4.27.3)(terser@5.34.1)(typescript@5.7.2)) + '@expressive-code/plugin-line-numbers': + specifier: 0.38.3 + version: 0.38.3 '@types/node': specifier: 20.16.10 version: 20.16.10 @@ -1122,6 +1125,9 @@ packages: '@expressive-code/plugin-frames@0.38.3': resolution: {integrity: sha512-qL2oC6FplmHNQfZ8ZkTR64/wKo9x0c8uP2WDftR/ydwN/yhe1ed7ZWYb8r3dezxsls+tDokCnN4zYR594jbpvg==} + '@expressive-code/plugin-line-numbers@0.38.3': + resolution: {integrity: sha512-QbK9NL44ST9w5ANVEu0a7fkjlq+fXgxyPqiSyFC4Nw/sAXd0MUwT1C8V0qlve4pZYLz53CR9tn4JQQbR0Z1tOg==} + '@expressive-code/plugin-shiki@0.38.3': resolution: {integrity: sha512-kqHnglZeesqG3UKrb6e9Fq5W36AZ05Y9tCREmSN2lw8LVTqENIeCIkLDdWtQ5VoHlKqwUEQFTVlRehdwoY7Gmw==} @@ -5585,6 +5591,10 @@ snapshots: dependencies: '@expressive-code/core': 0.38.3 + '@expressive-code/plugin-line-numbers@0.38.3': + dependencies: + '@expressive-code/core': 0.38.3 + '@expressive-code/plugin-shiki@0.38.3': dependencies: '@expressive-code/core': 0.38.3